Description
Hello 🐦
In my app I want the following behavior while using ScrollViewState
under the hood:
A user runs the app and sees e.g. a log. The log is rendered using ScrollView
+ScrollViewState
.
The log regularly gets updates and grows.
Because I can call .scroll_to_bottom()
during each render, the user always sees the latest log entries.
Now, the user scrolls up the log and observes older entries. Even though new entries get added to the log, the view remains fixed on the position the user scrolled to.
Later, the user scrolls back down to end of the scroll view, seeing the latest entries again.
When new entries are added, the view remains at the bottom as before.
Here are some options that I believe make ScrollView
easier to use. Let me know if you have further questions. Should you accept my proposal, I would love to file a PR.
My current solution
The current solution works fine but feels a bit unclean. I manually keep track on the scroll position, replicating work that is already been done inside ScrollViewState
iirc.
event_loop(..) {
MouseEventKind::ScrollDown => {
self.scroll_position = self.scroll_position.saturating_sub(1);
self.follow_the_bottom = self.scroll_position == 0;
self.scroll_state.scroll_down();
}
MouseEventKind::ScrollUp => {
self.follow_the_bottom = false;
if self.scroll_state.offset().y != 0 {
self.scroll_position = self.scroll_position.saturating_add(1);
}
self.scroll_state.scroll_up();
}
}
/* ... */
fn draw(...) {
if self.follow_the_bottom {
self.scroll_state.scroll_to_bottom()
}
}
Proposed solution
The ScrollViewState
can just tell me where the scroll position is.
event_loop(..) {
MouseEventKind::ScrollDown => {
self.scroll_state.scroll_down();
self.follow_the_bottom = self.scroll_state.is_at_bottom();
}
MouseEventKind::ScrollUp => {
self.follow_the_bottom = false;
self.scroll_state.scroll_up();
}
}
/* ... */
fn draw(...) {
if self.follow_the_bottom {
self.scroll_state.scroll_to_bottom()
}
}
Alternative solution
Let me ask for the size of the scroll view. Theoretically, I could calculate this info myself but in practice, that leads to code in the event loop (or where ever you have your "business" logic) reasoning about the ui layout. It's not too bad but it feels wrong to me.
The ScrollViewState
can just tell me where the scroll position is.
event_loop(..) {
MouseEventKind::ScrollDown => {
self.scroll_state.scroll_down();
self.follow_the_bottom = self.scroll_state.offset().y == self.scroll_state.size.height();
}
MouseEventKind::ScrollUp => {
self.follow_the_bottom = false;
self.scroll_state.scroll_up();
}
}
/* ... */
fn draw(...) {
if self.follow_the_bottom {
self.scroll_state.scroll_to_bottom()
}
}