Interaction topic

Interaction

This is part of the kalender documentation.

What the user can do inside a view: create, reschedule, resize, snap and zoom. Reacting to what they did is separate, see Controllers & Callbacks.


Interaction & Snapping

interaction sets what the user may do. Set on KalenderView, it applies to every view. MultiDayHeader, MultiDayBody, MonthBody and ScheduleBody also accept it and use their own over the calendar's, so a calendar can allow different things in its header than in its body. snapping is accepted by MultiDayBody only.

Both blocks below show every option at its default value.

KalenderView(
  eventsController: eventsController,
  kalenderController: kalenderController,
  interaction: KalenderInteraction(
    allowResizing: true,
    allowRescheduling: true,
    allowEventCreation: true,
    // Tap on desktop, long-press on mobile, when left unset.
    createEventGesture: EventInteractionGesture.tap,
    // The gesture that starts modifying an existing event, same defaults.
    modifyEventGesture: EventInteractionGesture.tap,
    // Input mode affects resize handle positioning and visibility:
    //   auto:      detects dynamically from pointer events
    //   precise:   mouse, stylus, trackpad (full-width handles, hover-to-show)
    //   imprecise: touch/finger (corner handles, selection-to-show)
    inputMode: InputMode.auto,
    // Opt in to horizontal resize handles in imprecise/touch mode.
    allowHorizontalImpreciseResize: false,
  ),
)
MultiDayBody(
  snapping: KalenderSnapping(
    snapIntervalMinutes: 10,
    snapToTimeIndicator: true,
    snapToOtherEvents: true,
    snapRange: const Duration(minutes: 15),
    eventSnapStrategy: const EventSnapStrategy.interval(),
  ),
)

Snapping strategies

eventSnapStrategy decides where a dragged event lands. EventSnapStrategy.interval(), the default, snaps to the nearest multiple of snapIntervalMinutes. EventSnapStrategy.none() leaves the cursor position alone. snapToTimeIndicator and snapToOtherEvents apply either way.

For anything else, extend EventSnapStrategy and override snap. Compare on runtimeType in ==, as Layout describes for the layout strategies and for the same reason.


Locking a single event

KalenderInteraction applies to the whole calendar. To hold one event in place while the rest stay editable, give it an EventInteraction. Anything the event forbids stays forbidden even where the calendar allows it.

KalenderEvent(
  start: range.start,
  end: range.end,
  // Movable, but its start and end are fixed.
  interaction: EventInteraction(
    allowStartResize: false,
    allowEndResize: false,
    allowRescheduling: true,
  ),
)

EventInteraction.allowNone() makes an event fully read-only, and EventInteraction.allowAll() is the default every event gets. A subclass passes it through with super.interaction, as in Custom Events.


Zoom

Zoom the calendar in and out by changing the heightPerMinute value on the MultiDayViewController. The web_demo example shows a full implementation with ZoomDetector.

To zoom with Ctrl+scroll on desktop, wrap KalenderView in a Listener:

import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';

Listener(
  onPointerSignal: (event) {
    if (!HardwareKeyboard.instance.isControlPressed) return;
    if (event is! PointerScrollEvent) return;

    final viewController = kalenderController.viewController;
    if (viewController is! MultiDayViewController) return;

    final heightPerMinute = viewController.heightPerMinute;
    final delta = event.scrollDelta.dy.sign * -0.1;
    heightPerMinute.value = (heightPerMinute.value + delta).clamp(0.5, 2.0);
  },
  child: KalenderView(
    eventsController: eventsController,
    kalenderController: kalenderController,
  ),
)

Classes

DefaultResizeHandles Interaction
The default layout for the resize handles of an event tile.
EventInteraction Interaction
What users may do with one event: resize its start, resize its end and reschedule it.
EventSnapStrategy Interaction
Decides where a dragged event lands, given the position of the cursor.
IntervalSnapStrategy Interaction
Snaps to the nearest multiple of the snap interval.
KalenderInteraction Interaction
What users may do with the calendar: resize, reschedule and create events, and with which gestures.
KalenderSnapping Interaction
How a dragged or resized event snaps to time intervals, the time indicator and other events.
NoSnapStrategy Interaction
Returns the cursor position unchanged.
PageTriggerConfiguration Interaction
The configuration for the page triggers.
ResizeDetector Interaction
The draggable that detects a resize gesture, wrapping the handle widget from TileComponents.verticalResizeHandle or TileComponents.horizontalResizeHandle.
ResizeHandleDetails Interaction
What a ResizeHandlePositioner needs to lay out the resize handles of one event tile.
ScrollTriggerConfiguration Interaction
The configuration for the scroll triggers.

Mixins

DragTargetUtilities<T extends StatefulWidget> Interaction
Shared drag-target behaviour for the calendar's DragTarget states.

Constants

kDefaultSnapStrategy → const EventSnapStrategy Interaction
The strategy a calendar uses when nothing overrides it.

Enums

EventInteractionGesture Interaction
The EventInteractionGesture is used to differentiate between the different ways to create and modify an event.
InputMode Interaction
The InputMode defines the type of input the calendar should optimize for.
ResizeDirection Interaction
The direction an event is resized in.

Typedefs

HorizontalTriggerWidgetBuilder = Widget Function(BuildContext context, double pageWidth) Interaction
The trigger widget builder, should be constrained in width.
OnWillAcceptWithDetailsHorizontal = bool Function(DragTargetDetails<Object?> details, KalenderController controller, HorizontalConfiguration configuration) Interaction
The callback for when a drag target is evaluating whether to accept a draggable.
OnWillAcceptWithDetailsVertical = bool Function(DragTargetDetails<Object?> details, KalenderController controller, VerticalConfiguration configuration) Interaction
The callback for when a drag target is evaluating whether to accept a draggable.
ResizeHandlePositioner = Widget Function(BuildContext context, ResizeHandleDetails details) Interaction
The builder that positions the resize handles of an event tile.
VerticalTriggerWidgetBuilder = Widget Function(BuildContext context, double pageWidth) Interaction
The trigger widget builder, should be constrained in height.