getAlignmentFromGlobalPosition static method

double getAlignmentFromGlobalPosition(
  1. Offset globalPosition,
  2. BuildContext context,
  3. int itemCount, {
  4. Axis direction = Axis.horizontal,
  5. bool mirrorForRtl = true,
})

Converts a global drag position to alignment (-1 to 1) along direction.

Applies rubber band resistance when dragging beyond edges.

Parameters:

  • globalPosition: The global position from drag details
  • context: Build context to find the render box
  • itemCount: Total number of items
  • direction: Axis whose coordinate and extent drive the mapping
  • mirrorForRtl: Whether to mirror the horizontal fraction under an RTL Directionality. Leave true for consumers that position the indicator with AlignmentDirectional (the segmented controls), where the framework does not re-apply the flip. Pass false for consumers working in physical alignment space: the bottom and searchable tab bars paint with Alignment and carry RTL in their tab data, so mirroring here flips a second time and runs the drag backwards. It would also disagree with tabIndexFromGlobalPosition, which never mirrors — which is why a press landed on the right tab and the slide then ran the wrong way.

Returns: Alignment value with rubber band resistance applied.

Implementation

static double getAlignmentFromGlobalPosition(
  Offset globalPosition,
  BuildContext context,
  int itemCount, {
  Axis direction = Axis.horizontal,
  bool mirrorForRtl = true,
}) {
  final box = context.findRenderObject()! as RenderBox;
  final localPosition = box.globalToLocal(globalPosition);

  // Calculate the effective draggable range
  final indicatorWidth = 1.0 / itemCount;
  final draggableRange = 1.0 - indicatorWidth;
  final padding = indicatorWidth / 2;

  // Map drag position to 0-1 range
  final mainPosition =
      direction == Axis.horizontal ? localPosition.dx : localPosition.dy;
  final mainExtent =
      direction == Axis.horizontal ? box.size.width : box.size.height;
  var rawRelativeX = (mainPosition / mainExtent).clamp(0.0, 1.0);

  if (mirrorForRtl &&
      direction == Axis.horizontal &&
      Directionality.of(context) == TextDirection.rtl) {
    rawRelativeX = 1.0 - rawRelativeX;
  }

  final normalizedX = (rawRelativeX - padding) / draggableRange;

  // Apply rubber band resistance for overdrag
  final adjustedRelativeX = applyRubberBandResistance(normalizedX);

  // Convert to -1 to 1 range
  return (adjustedRelativeX * 2) - 1;
}