Introduce `on_scroll` event in `Scrollable`

This commit is contained in:
Héctor Ramón 2021-06-04 20:46:27 +07:00
parent 57510c43c8
commit 3051d4ec76
1 changed files with 47 additions and 1 deletions

View File

@ -23,6 +23,7 @@ pub struct Scrollable<'a, Message, Renderer: self::Renderer> {
scrollbar_margin: u16, scrollbar_margin: u16,
scroller_width: u16, scroller_width: u16,
content: Column<'a, Message, Renderer>, content: Column<'a, Message, Renderer>,
on_scroll: Option<Box<dyn Fn(f32) -> Message>>,
style: Renderer::Style, style: Renderer::Style,
} }
@ -37,6 +38,7 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
scrollbar_margin: 0, scrollbar_margin: 0,
scroller_width: 10, scroller_width: 10,
content: Column::new(), content: Column::new(),
on_scroll: None,
style: Renderer::Style::default(), style: Renderer::Style::default(),
} }
} }
@ -101,12 +103,22 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
} }
/// Sets the scroller width of the [`Scrollable`] . /// Sets the scroller width of the [`Scrollable`] .
/// Silently enforces a minimum value of 1. ///
/// It silently enforces a minimum value of 1.
pub fn scroller_width(mut self, scroller_width: u16) -> Self { pub fn scroller_width(mut self, scroller_width: u16) -> Self {
self.scroller_width = scroller_width.max(1); self.scroller_width = scroller_width.max(1);
self self
} }
/// Sets a function to call when the [`Scrollable`] is scrolled.
///
/// The function takes the new relative offset of the [`Scrollable`]
/// (e.g. `0` means top, while `1` means bottom).
pub fn on_scroll(mut self, f: impl Fn(f32) -> Message + 'static) -> Self {
self.on_scroll = Some(Box::new(f));
self
}
/// Sets the style of the [`Scrollable`] . /// Sets the style of the [`Scrollable`] .
pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self { pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self {
self.style = style.into(); self.style = style.into();
@ -121,6 +133,24 @@ impl<'a, Message, Renderer: self::Renderer> Scrollable<'a, Message, Renderer> {
self.content = self.content.push(child); self.content = self.content.push(child);
self self
} }
fn notify_on_scroll(
&self,
bounds: Rectangle,
content_bounds: Rectangle,
messages: &mut Vec<Message>,
) {
if content_bounds.height <= bounds.height {
return;
}
if let Some(on_scroll) = &self.on_scroll {
messages.push(on_scroll(
self.state.offset.absolute(bounds, content_bounds)
/ (content_bounds.height - bounds.height),
));
}
}
} }
impl<'a, Message, Renderer> Widget<Message, Renderer> impl<'a, Message, Renderer> Widget<Message, Renderer>
@ -228,6 +258,8 @@ where
} }
} }
self.notify_on_scroll(bounds, content_bounds, messages);
return event::Status::Captured; return event::Status::Captured;
} }
Event::Touch(event) => { Event::Touch(event) => {
@ -251,6 +283,12 @@ where
self.state.scroll_box_touched_at = self.state.scroll_box_touched_at =
Some(cursor_position); Some(cursor_position);
self.notify_on_scroll(
bounds,
content_bounds,
messages,
);
} }
} }
touch::Event::FingerLifted { .. } touch::Event::FingerLifted { .. }
@ -290,6 +328,8 @@ where
content_bounds, content_bounds,
); );
self.notify_on_scroll(bounds, content_bounds, messages);
return event::Status::Captured; return event::Status::Captured;
} }
} }
@ -317,6 +357,12 @@ where
self.state.scroller_grabbed_at = self.state.scroller_grabbed_at =
Some(scroller_grabbed_at); Some(scroller_grabbed_at);
self.notify_on_scroll(
bounds,
content_bounds,
messages,
);
return event::Status::Captured; return event::Status::Captured;
} }
} }