Managing Radial Pan Events in Flutter

One UI element not natively supported in Flutter is a click wheel, rotary control, or radial knob. The following snippet demonstrates how to create a circular container and detect the direction (clockwise or counterclockwise) and velocity of user rotation.

Access the complete source code for the wheel demo.

Flutter Circular Pan Wheel

Detecting Pan Gestures

Utilize a GestureDetector to encompass a circular container with a BoxShape.circle. Each pan event on the circle will generate data containing movement information.

file_type_dartlang main.dart
int radius = 250;

GestureDetector(
    onPanUpdate: _panHandler,
    child: Container(
        height: radius * 2,
        width: radius * 2,
        decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.red,
        ),
    )
)

Computing Rotational Movement

Divide the wheel into four separate quadrants: topRight, bottomRight, bottomLeft, and topLeft. Each quadrant allows four directions of movement: up, down, left, or right. Determine the change in movement by examining the delta and adjust it according to the quadrant.

The resulting value, rotationalChange, indicates clockwise rotation if positive, and counterclockwise if negative. Utilize this value to effect meaningful changes in the UI.

file_type_dartlang main.dart
  void _panHandler(DragUpdateDetails d) {

    /// Determine pan location on the wheel
    bool onTop = d.localPosition.dy <= radius;
    bool onLeftSide = d.localPosition.dx <= radius;
    bool onRightSide = !onLeftSide;
    bool onBottom = !onTop;

    /// Determine pan movements
    bool panUp = d.delta.dy <= 0.0;
    bool panLeft = d.delta.dx <= 0.0;
    bool panRight = !panLeft;
    bool panDown = !panUp;

    /// Absolute change on axis
    double yChange = d.delta.dy.abs();
    double xChange = d.delta.dx.abs();

    /// Determine directional change on wheel
    double verticalRotation = (onRightSide && panDown) || (onLeftSide && panUp)
        ? yChange
        : yChange * -1;

    double horizontalRotation = (onTop && panRight) || (onBottom && panLeft) 
        ? xChange 
        : xChange * -1;

    // Compute total change
    double rotationalChange = verticalRotation + horizontalRotation; 

    bool movingClockwise = rotationalChange > 0;
    bool movingCounterClockwise = rotationalChange < 0;

    // Perform relevant actions based on computations
  }

Incorporating Velocity

Enhance user experience by adding velocity, particularly if the UI element controls a scrollable view. The velocity increases proportionally to the speed of the user’s panning motion. Simply multiply the rotational change by the delta distance.

file_type_dartlang main.dart
double rotationalChange = (horz + vert) * d.delta.distance;

Comments

Load Comments