GestureDetector
Every tap, drag, scale, and trackpad callback with details types.
First-class Flutter-style detector: tap, double-tap, long-press, pan,
directional drag, scale, and trackpad. Default behavior DeferToChild.
A tappable counter — copy, paste, and run:
use incular::prelude::*;
use incular::gestures::TapDownDetails;
use incular::widgets::HitTestBehavior;
fn main() {
let count = Signal::new(0u32);
let app = Application::new(move |_cx| {
let tapped = count.clone();
Container::builder()
.padding(EdgeInsets::all(24.0))
.alignment(Alignment::CENTER)
.child(
GestureDetector::new(Text::new("Tap me"))
.on_tap(move || tapped.update(|c| *c += 1))
.on_tap_down(|_d: TapDownDetails| {})
.on_double_tap(|| {})
.on_long_press(|| {})
.on_pan_update(|_delta: Offset| {})
.behavior(HitTestBehavior::Opaque),
)
.build()
.into()
})
.expect("valid application");
incular::run(app).expect("run application");
}The full callback tour (on_tap_up, on_double_tap_down,
on_long_press_start, on_pan_start, directional drags, on_scale_update,
on_trackpad_gesture, focus_node, autofocus) shares the same builder
shape; see the Methods table below.
// Full callback tour (attach to any child; each line typechecks):
// .on_tap_up(|d: TapUpDetails| {})
// .on_double_tap_down(|d: TapDownDetails| {})
// .on_long_press_start(|d: LongPressStartDetails| {})
// .on_pan_start(|d: DragStartDetails| {})
// .on_horizontal_drag_start(|d: DragStartDetails| {})
// .on_scale_update(|d: ScaleUpdateDetails| {})
// .on_trackpad_gesture(|g: TrackpadGesture| {})
// .focus_node(node)
// .autofocus(true)Missing child renders SizedBox::shrink().
| Callback group | Methods |
|---|---|
| Tap | on_tap, on_tap_down, on_tap_up, on_tap_cancel |
| Double tap | on_double_tap, on_double_tap_down, on_double_tap_cancel |
| Long press | on_long_press, on_long_press_start, on_long_press_move_update, on_long_press_up, on_long_press_end |
| Pan | on_pan_down, on_pan_start, on_pan_update, on_pan_end, on_pan_cancel |
| Directional drag | on_horizontal_drag_*, on_vertical_drag_* (down/start/update/end/cancel each) |
| Scale | on_scale_start, on_scale_update, on_scale_end |
| Trackpad | on_trackpad_gesture |
| Lifecycle | on_cancel, behavior, callbacks, focus_node, autofocus |
use incular::prelude::*;
fn main() {
let count = Signal::new(0u32);
let app = Application::new(move |_cx| {
let tapped = count.clone();
GestureDetector::new(Text::new("Tap me"))
.on_tap(move || tapped.update(|c| *c += 1)).into()
})
.expect("valid application");
incular::run(app).expect("run application");
}See HitTestBehavior for hit-test contracts and
Raw Input for arena-free listeners.
Drag and drop
A shared DragDropContext<T> connects drag sources and targets — copy,
paste, and run:
use incular::prelude::*;
fn main() {
let context = DragDropContext::<String>::new();
let target_context = context.clone();
let app = Application::new(move |_cx| {
Container::builder()
.padding(EdgeInsets::all(24.0))
.alignment(Alignment::CENTER)
.child(
Column::builder()
.main_axis_size(MainAxisSize::Min)
.spacing(8.0)
.children(Vec::<Widget>::from([
Draggable::new(
context.clone(),
"file.txt".to_string(),
Text::new("Drag me"),
)
.feedback(|payload| {
Text::new(format!("Moving {payload}")).into()
})
.on_start(|payload| println!("start {payload}"))
.on_end(|payload| println!("end {payload}"))
.on_cancel(|payload| println!("cancel {payload}")).into(),
DragTarget::new(
target_context.clone(),
Text::new("Drop here"),
)
.on_will_accept(|payload: String| !payload.is_empty())
.on_enter(|payload| println!("enter {payload}"))
.on_leave(|payload| println!("leave {payload}"))
.on_drop(|payload| println!("dropped {payload}")).into(),
Dismissible::new(
DismissDirection::Horizontal,
Text::new("Swipe me"),
|direction| println!("dismissed {direction:?}"),
)
.threshold(0.5).into(),
]))
.build(),
)
.build()
.into()
})
.expect("valid application");
incular::run(app).expect("run application");
}Cross-window transfer and lazy-list reordering are intentionally out of scope
for the local contract. DismissDirection: Horizontal / Vertical — the
axis a Dismissible may claim. LongPressDraggable starts drags after a
long-press instead of immediately.
Related: Focus.