PullToRefresh¶
Header: winui/ui/scrolling/PullToRefresh.hpp. Spec: winui/ui/scrolling/PullToRefresh.hpp.
A container that refreshes its content when it is pulled past its start, with a progress indicator. The pull is a mouse drag.
A pull starts once a drag mostly along pull_direction() passes 8 DIPs, and only while the content is scrolled to the edge the pull comes from. The content is anything with Element::scroll_info(), such as a Scroll or a ListView. It follows the pointer, and a 100 DIP visualizer slides in behind it, its indicator turning with the pull. The indicator is a Refresh symbol, or what set_visualizer_content() installs. Releasing past 80 % of the visualizer (Pending) refreshes: the state goes to Refreshing, on_refresh_requested() fires once, and the refresh lasts until the app calls complete_refresh(). ui::PullToRefresh is the declarative form.
Example:
ui::Control<ui::PullToRefresh> refresh;
window.set_content(ui::PullToRefresh{
.height = 400.0f,
.on_refresh_requested = [&refresh] {
// Start reloading; when the new data is in (now or later, e.g. from a timer):
refresh->complete_refresh(); // back to Idle
},
.control = refresh,
.content = ui::Scroll{.content = ui::VerticalStack{.content = {
ui::Text{.text = "Item 1"},
ui::Text{.text = "Item 2"},
}}},
});
// Imperatively, pulling up from the bottom:
auto ptr = std::make_unique<ui::PullToRefreshControl>();
ui::ScrollControl* scroll = ptr->set_content(std::make_unique<ui::ScrollControl>());
ptr->set_pull_direction(ui::RefreshPullDirection::BottomToTop);
ptr->on_refresh_state_changed([](const ui::PullToRefreshStateChangedArgs& args) { /* e.g. show a status text */ });
ptr->request_refresh(); // refresh programmatically, without a pull
ui::PullToRefresh¶
Pull one child with the mouse to refresh it. Builds a ui::PullToRefreshControl. on_refresh_requested fires once, and the app calls .control's complete_refresh() when the work it started, typically an async data fetch, has finished.
Example:
void start_fetch(ui::Action done); // the app's own async work
ui::Control<ui::PullToRefresh> pull;
window.set_content(ui::PullToRefresh{
.height = 400.0f,
.on_refresh_requested = [&]
{
start_fetch([&] { pull->complete_refresh(); });
},
.control = pull,
.content = ui::Scroll{.content = ui::VerticalStack{.content = {
ui::Text{.text = "Item 1"},
ui::Text{.text = "Item 2"},
}}},
});
Every field, in the order a designated initializer names them:
ui::PullToRefresh{
.pull_direction, .visualizer_orientation, .style, .margin, .width, .height, .min_width,
.min_height, .max_width, .max_height, .horizontal_alignment, .vertical_alignment, .visible,
.tool_tip, .accessibility, .on_refresh_requested, .on_refresh_state_changed,
.on_pointer_entered, .on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down,
.on_wheel, .control, .content, .visualizer_content
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
pull_direction |
ui::Binding<ui::RefreshPullDirection> |
{ui::RefreshPullDirection::TopToBottom} |
Which edge the content is pulled from. |
visualizer_orientation |
ui::Binding<ui::RefreshVisualizerOrientation> |
{ui::RefreshVisualizerOrientation::Auto} |
How the indicator is turned. Auto turns it along the pull. |
on_refresh_requested |
ui::Callback<void()> |
Fires once per refresh; call complete_refresh() on .control when done. |
|
on_refresh_state_changed |
ui::Callback<void(const ui::PullToRefreshStateChangedArgs&)> |
Fires with the old and the new state (Idle, Interacting, Pending, Refreshing). | |
on_pointer_entered |
ui::Action |
The pointer moved onto the control. | |
on_pointer_exited |
ui::Action |
The pointer left the control. | |
on_got_focus |
ui::Action |
Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this. | |
on_lost_focus |
ui::Action |
Keyboard focus left the control and everything inside it. | |
on_key_down |
ui::Callback<ui::Handling(const ui::KeyEvent&)> |
A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()). | |
on_wheel |
ui::Callback<ui::Handling(const ui::PointerEvent&)> |
A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()). | |
control |
ui::ControlOut<ui::PullToRefresh> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The pulled content, typically a ui::Scroll or a list. | |
visualizer_content |
ui::Spec |
What turns as the list is pulled, in place of the Refresh symbol. |
Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, accessibility every spec carries (conventions).
build¶
Consumes the spec and returns the built ui::PullToRefreshControl; the caller owns it.
ui::PullToRefreshControl¶
Derives from ui::Element.
A container that refreshes its content when it is pulled past its start, with a progress indicator. The pull is a mouse drag.
A pull starts once a drag mostly along pull_direction() passes 8 DIPs, and only while the content is scrolled to the edge the pull comes from. The content is anything with Element::scroll_info(), such as a Scroll or a ListView. It follows the pointer, and a 100 DIP visualizer slides in behind it, its indicator turning with the pull. The indicator is a Refresh symbol, or what set_visualizer_content() installs. Releasing past 80 % of the visualizer (Pending) refreshes: the state goes to Refreshing, on_refresh_requested() fires once, and the refresh lasts until the app calls complete_refresh(). ui::PullToRefresh is the declarative form.
Example:
ui::Control<ui::PullToRefresh> refresh;
window.set_content(ui::PullToRefresh{
.height = 400.0f,
.on_refresh_requested = [&refresh] {
// Start reloading; when the new data is in (now or later, e.g. from a timer):
refresh->complete_refresh(); // back to Idle
},
.control = refresh,
.content = ui::Scroll{.content = ui::VerticalStack{.content = {
ui::Text{.text = "Item 1"},
ui::Text{.text = "Item 2"},
}}},
});
// Imperatively, pulling up from the bottom:
auto ptr = std::make_unique<ui::PullToRefreshControl>();
ui::ScrollControl* scroll = ptr->set_content(std::make_unique<ui::ScrollControl>());
ptr->set_pull_direction(ui::RefreshPullDirection::BottomToTop);
ptr->on_refresh_state_changed([](const ui::PullToRefreshStateChangedArgs& args) { /* e.g. show a status text */ });
ptr->request_refresh(); // refresh programmatically, without a pull
PullToRefreshControl¶
Pulls TopToBottom, with the default Refresh-symbol indicator and no content.
~PullToRefreshControl¶
set_content¶
Sets the content that is pulled and takes ownership of it. Returns a non-owning pointer to it.
content¶
The pulled content (non-owning), or nullptr.
set_visualizer_content¶
What spins as the list is pulled, instead of the Refresh symbol.
visualizer_content¶
The indicator element (non-owning): the default Refresh symbol, or what set_visualizer_content() installed.
pull_direction¶
Which edge the content is pulled from; TopToBottom by default. Changing it mid-pull ends the pull.
set_pull_direction¶
Lays the control out again and redraws.
visualizer_orientation¶
How the indicator is turned; Auto by default.
set_visualizer_orientation¶
Marks the control for redraw.
state¶
The visualizer's current state; Idle by default.
pull_distance¶
How far the content is pushed along the pull, in [0, 100].
interaction_ratio¶
How far the pull has come, as pull_distance() over the visualizer's 100 DIPs, in [0, 1].
request_refresh¶
Starts a refresh at once and raises on_refresh_requested. Does nothing while refreshing.
complete_refresh¶
Ends the refresh and goes back to Idle.
on_refresh_state_changed¶
Fires with the old and the new state.
on_refresh_requested¶
Fires when a refresh starts; the refresh lasts until complete_refresh().
for_each_child¶
Visits the content only. The indicator takes no focus, so it is added separately to the visual tree and the accessibility tree while it shows (below).
automation_children¶
The content, then the indicator while it is pulled into view.
build_visual_tree_override¶
Adds the indicator while it is pulled into view.
measure_override¶
Implement these instead of measure() and arrange(). The base class has already applied margin, size limits and alignment by the time these run. measure_override() is pure (every concrete Element must size itself); arrange_override() defaults to a no-op since most leaves need nothing beyond having bounds() set, which the base already did.
arrange_override¶
Position children within the rect arrange() settled on (also in bounds(), window DIPs). Default: nothing, for a leaf.
render_override¶
What the control draws, in layout coordinates; render() has already applied the visual layer. A container draws its children through their render(), never their render_override().
pointer_override¶
Drives the pull from a mouse drag; other pointer input goes to the content.
handled_pointer_override¶
A press and release the content took still start and end a pull.
clear_dirty_override¶
Clears the dirty flags of the content and of the indicator, whether it shows or not.
tick_override¶
Advances the settle, Pending pulse and Refreshing spin animations, and ticks the content and the indicator.
struct PullToRefreshStateChangedArgs¶
What on_refresh_state_changed gets: the state before and after the change.
| Field | Type | Default | |
|---|---|---|---|
old_state |
PullToRefreshState |
PullToRefreshState::Idle |
The state it left. |
new_state |
PullToRefreshState |
PullToRefreshState::Idle |
The state it is in now. |
Enumerations¶
RefreshPullDirection¶
Which way the content is pulled.
| Value | |
|---|---|
LeftToRight |
Pulled rightwards from the left edge, while scrolled to the start. |
TopToBottom |
Pulled down from the top, while scrolled to the start (the default). |
RightToLeft |
Pulled leftwards from the right edge, while scrolled to the end. |
BottomToTop |
Pulled up from the bottom, while scrolled to the end. |
RefreshVisualizerOrientation¶
How the indicator is turned.
| Value | |
|---|---|
Auto |
Turned along the pull. |
Normal |
Upright. |
Rotate90DegreesCounterclockwise |
Turned by +90 degrees. |
Rotate270DegreesCounterclockwise |
Turned by -90 degrees. |
PullToRefreshState¶
Where a pull to refresh is: idle, being pulled, armed or refreshing.
| Value | |
|---|---|
Idle |
Not pulled and not refreshing. |
Interacting |
Pulled, but not far enough to refresh. |
Pending |
Pulled far enough, so a release now refreshes. |
Refreshing |
Refreshing until complete_refresh(). |
Tests¶
tests/test_pull_to_refresh.cpp