Skip to content

RefreshBox

RefreshBox coordinates pull gestures with nested scrolling. It does not fetch data or own the truth of whether a refresh is running.

#include <huxerui/huxerui.h>
#include <chrono>
using namespace huxerui;
using namespace std::chrono_literals;
[[huxerui::composable]]
View RefreshableFeed() {
auto refreshing = UseState(false);
auto completed = UseState(0);
auto tasks = UseTaskScope();
return RefreshBox(
ScrollView(Column {
Text::Format("Completed refreshes: {}", completed),
Text("Pull down at the start of this list."),
}),
refreshing
).OnRefresh([refreshing, completed, tasks] {
refreshing = true;
tasks.Launch([refreshing, completed]() -> Task<void> {
co_await Delay(800ms);
++completed;
refreshing = false;
});
}).With(Frame{.height = 320.0F});
}

The delay is a visible demonstration; replace it with your own request and ensure both success and failure clear the controlled flag. Work belongs to the owning TaskScope, not to the gesture recognizer.

Declared by <huxerui/view.h>: RefreshBox(View content, bool refreshing) and the State form. .OnRefresh(void()) requests work after a qualifying pull; set refreshing promptly to acknowledge it. Setting the flag programmatically shows the indicator without emitting a new request.

RefreshBoxStyle controls the theme’s indicator and geometry. The child remains responsible for its scrolling content and bounded layout. Use ordinary state to retain fetched data.

See Tasks for cancellation and the example source.

The wrapper reacts to qualifying direct pull remaining at the leading scroll boundary. Ordinary wheel scrolling is not a request to refresh. Its accessibility refresh action uses the same OnRefresh(void()) callback. The child can be a ScrollView, VirtualList, or another participating scroll subtree; RefreshBox does not replace its data source or scrolling policy.

When a request arrives, set refreshing = true before launching asynchronous work. Clear it after success or handled failure. Programmatic refreshing = true is also useful for a visible Reload button and does not emit another OnRefresh. Keep errors separate from that bool so the indicator can settle while the page explains the failure.

RefreshBoxStyle field Effect
indicator ProgressCircleStyle for determinate pulling and indeterminate refreshing.
container_color, container_size Indicator backing surface and diameter.
pull_resistance Fraction of unconsumed direct pull retained as displacement.
maximum_pull_distance, trigger_distance Pull limit and release threshold.
refresh_distance Displacement retained while refreshing.
settle_motion TweenSpec for reveal/settlement.

Tune the threshold and maximum together. Changing these visuals does not alter request cancellation or the lifetime of the task that fetches the feed.