Added support for fling on touch devices.

This commit is contained in:
Cyannide 2025-05-10 11:22:13 -05:00
parent 17d4cfb263
commit eb3f8f9b10
1 changed files with 42 additions and 9 deletions

View File

@ -30,6 +30,7 @@ impl Plugin for ScrollViewPlugin {
input_mouse_pressed_move, input_mouse_pressed_move,
input_touch_pressed_move, input_touch_pressed_move,
scroll_events, scroll_events,
fling_update,
scroll_update, scroll_update,
) )
.chain(), .chain(),
@ -44,12 +45,18 @@ pub struct ScrollView {
/// Field which control speed of the scrolling. /// Field which control speed of the scrolling.
/// Could be negative number to implement invert scroll /// Could be negative number to implement invert scroll
pub scroll_speed: f32, pub scroll_speed: f32,
/// Amount of friction to apply to slow down the fling
pub friction: f32,
/// Current vertical velocity
pub velocity: f32,
} }
impl Default for ScrollView { impl Default for ScrollView {
fn default() -> Self { fn default() -> Self {
Self { Self {
scroll_speed: 1200.0, scroll_speed: 1200.0,
friction: 4.2,
velocity: 0.0,
} }
} }
} }
@ -174,24 +181,19 @@ fn update_size(
fn input_touch_pressed_move( fn input_touch_pressed_move(
touches: Res<Touches>, touches: Res<Touches>,
mut q: Query<(&Children, &Interaction), With<ScrollView>>, mut q: Query<(&Interaction, &mut ScrollView)>,
mut content_q: Query<&mut ScrollableContent>, time: Res<Time>,
) { ) {
for t in touches.iter() { for t in touches.iter() {
let Some(touch) = touches.get_pressed(t.id()) else { let Some(touch) = touches.get_pressed(t.id()) else {
continue; continue;
}; };
for (children, &interaction) in q.iter_mut() { for (&interaction, mut view) in q.iter_mut() {
if interaction != Interaction::Pressed { if interaction != Interaction::Pressed {
continue; continue;
} }
for child in children.iter() { view.velocity = (view.velocity + touch.delta().y / time.delta_secs()) / 2.0;
let Ok(mut scroll) = content_q.get_mut(child) else {
continue;
};
scroll.scroll_by(touch.delta().y);
}
} }
} }
} }
@ -232,3 +234,34 @@ fn scroll_update(mut q: Query<(&ScrollableContent, &mut Node), Changed<Scrollabl
style.top = Val::Px(scroll.pos_y); style.top = Val::Px(scroll.pos_y);
} }
} }
fn fling_update(
mut q_view: Query<(&mut ScrollView, &Children)>,
mut q_scroll: Query<&mut ScrollableContent>,
time: Res<Time>,
) {
for (mut view, children) in q_view.iter_mut() {
let mut iter = q_scroll.iter_many_mut(children);
while let Some(mut scroll) = iter.fetch_next() {
if view.velocity.abs() > 16.0 {
let (value, velocity) = calc_velocity(
scroll.pos_y,
view.velocity,
-view.friction,
time.delta_secs(),
);
view.velocity = velocity;
scroll.pos_y = value.clamp(-scroll.max_scroll, 0.);
} else {
view.velocity = 0.0;
}
}
}
}
fn calc_velocity(value: f32, velocity: f32, friction: f32, delta_t: f32) -> (f32, f32) {
(
value - velocity / friction + velocity / friction * (friction * delta_t).exp(),
velocity * (delta_t * friction).exp(),
)
}