Open
Description
What problem does this solve or what need does it fill?
Scroll list with clickable items on mobile. Need a way to know when the pointer is dragged when the pointer is released/click.
What solution would you like?
//! Scrollable list with clickable items in 0.16.0 on mobile.
//!
//! Scroll by drag and click only without drag started.
//!
//! Maybe something like `PointerDragging` and `update_pointer_dragging` must be implemented in bevy?
//!
//! I write small example how I do this:
use bevy::{
color::palettes::tailwind, picking::pointer::PointerId, platform::collections::HashSet,
prelude::*,
};
fn spawn_camera(mut commands: Commands) {
commands.spawn(Camera2d);
}
fn spawn_ui(mut commands: Commands) {
commands
.spawn(Node {
width: Val::Percent(100.),
height: Val::Percent(100.),
overflow: Overflow::scroll_y(),
flex_wrap: FlexWrap::Wrap,
row_gap: Val::Px(10.),
..Default::default()
})
.observe(scroll_drag)
.with_children(|s| {
for i in 1..=100 {
s.spawn((
Node {
width: Val::Percent(100.),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
padding: UiRect::vertical(Val::Px(20.)),
border: UiRect::all(Val::Px(2.)),
..Default::default()
},
BackgroundColor(tailwind::GRAY_500.into()),
BorderColor(tailwind::GRAY_300.into()),
))
.observe(item_click)
.with_child(Text::new(format!("Item #{i}")));
}
});
}
fn scroll_drag(trigger: Trigger<Pointer<Drag>>, mut node_query: Query<&mut ScrollPosition>) {
let Ok(mut scroll_position) = node_query.get_mut(trigger.target()) else {
return;
};
scroll_position.offset_y -= trigger.delta.y;
}
fn item_click(
trigger: Trigger<Pointer<Released>>,
state: Res<PointerDragging>,
text_query: Query<(&ChildOf, &Text)>,
) {
if state.contains(&(trigger.pointer_id, trigger.button)) {
return;
}
if let Some(text) = text_query
.iter()
.find_map(|(child_of, text)| (trigger.target() == child_of.parent()).then_some(text))
{
println!("Click at: {}", text.0);
};
}
#[derive(Debug, Default, Deref, DerefMut, Resource)]
struct PointerDragging(HashSet<(PointerId, PointerButton)>);
fn update_pointer_dragging(
mut state: ResMut<PointerDragging>,
mut drag_start_events: EventReader<Pointer<DragStart>>,
mut drag_end_events: EventReader<Pointer<DragEnd>>,
) {
for drag_start_event in drag_start_events.read() {
state.insert((drag_start_event.pointer_id, drag_start_event.button));
}
for drag_end_event in drag_end_events.read() {
state.remove(&(drag_end_event.pointer_id, drag_end_event.button));
}
}
fn main() {
App::new()
.init_resource::<PointerDragging>()
.add_plugins(DefaultPlugins)
.add_systems(Startup, (spawn_camera, spawn_ui))
.add_systems(Update, update_pointer_dragging)
.run();
}