getPositionForChild method

  1. @override
Offset getPositionForChild(
  1. Size areaSize,
  2. Size overlaySize
)
override

areaSize 容器尺寸 overlaySize 浮层尺寸 boxSize 目标组件尺寸 position 目标组件中心的坐标

Implementation

@override
Offset getPositionForChild(Size areaSize, Size overlaySize) {
  // print("===${areaSize}=====${overlaySize}===${boxSize}==${position}===");

  if (onSizeFind != null) {
    scheduleMicrotask(() {
      onSizeFind!(overlaySize);
    });
  }
  if (clickPosition != null) {
    return clickOffset(overlaySize.height, areaSize.height);
  }

  /// 计算溢出情况
  double y = position.dy;
  double x = position.dx;
  double capacityH = overlaySize.height + boxSize.height / 2 + gap;
  double capacityW = overlaySize.width + boxSize.width / 2 + gap;

  final OverflowEdge edge = OverflowEdge(
    left: x - capacityW < (margin?.left ?? 0),
    top: y - capacityH < (margin?.top ?? 0),
    right: x + capacityW > areaSize.width,
    bottom: y + capacityH > areaSize.height,
  );
  OverflowAlgorithm? algo = overflowAlgorithm ?? defaultOverflowAlgorithm;
  Placement effectPlacement = algo(edge, placement);

  if (edge.overflowAll) {
    return Offset(
      areaSize.width / 2 - overlaySize.width / 2,
      areaSize.height / 2 - overlaySize.height / 2,
    );
  }

  Offset center =
      position.translate(-overlaySize.width / 2, -overlaySize.height / 2);

  double halfWidth = (overlaySize.width - boxSize.width) / 2;
  double halfLeftWidth = (overlaySize.width + boxSize.width) / 2 + gap;
  double halfHeight = (overlaySize.height - boxSize.height) / 2;

  double verticalHeight = (overlaySize.height + boxSize.height) / 2 + gap;

  Offset translation = switch (effectPlacement) {
    Placement.top => Offset(0, -verticalHeight),
    Placement.topStart => Offset(halfWidth, -verticalHeight),
    Placement.topEnd => Offset(-halfWidth, -verticalHeight),
    Placement.bottom => Offset(0, verticalHeight),
    Placement.bottomStart => Offset(halfWidth, verticalHeight),
    Placement.bottomEnd => Offset(-halfWidth, verticalHeight),
    Placement.left => Offset(-halfLeftWidth, 0),
    Placement.leftStart => Offset(-halfLeftWidth, halfHeight),
    Placement.leftEnd => Offset(-halfLeftWidth, -halfHeight),
    Placement.right => Offset(halfLeftWidth, 0),
    Placement.rightStart => Offset(halfLeftWidth, halfHeight),
    Placement.rightEnd => Offset(halfLeftWidth, -halfHeight),
  };
  Offset result = center + translation;

  double dx = 0;
  double endEdgeDx = result.dx + overlaySize.width - areaSize.width;
  if (endEdgeDx > 0) {
    result = result.translate(-endEdgeDx, 0);
    dx = -endEdgeDx;
  }
  double startEdgeDy = result.dx;
  if (startEdgeDy < 0) {
    result = result.translate(-startEdgeDy, 0);
    dx = -startEdgeDy;
  }

  if (offsetCalculator != null) {
    result += offsetCalculator!(Calculator(
        placement: effectPlacement,
        boxSize: boxSize,
        overlaySize: overlaySize,
        gap: gap));
  }

  if (effectPlacement != placement || dx != 0) {
    scheduleMicrotask(() {
      onPlacementShift(PlacementShift(effectPlacement, dx));
    });
  }

  return result;
}