getPositionForChild method

  1. @override
Offset getPositionForChild(
  1. Size size,
  2. Size childSize
)
override

The position where the child should be placed.

The size argument is the size of the parent, which might be different from the value returned by getSize if that size doesn't satisfy the constraints passed to getSize. The childSize argument is the size of the child, which will satisfy the constraints returned by getConstraintsForChild.

Defaults to positioning the child in the upper left corner of the parent.

Implementation

@override
Offset getPositionForChild(Size size, Size childSize) {
  final targetOffset = constraints.targetOffset;
  final targetSize = constraints.targetSize;
  final screenSize = constraints.screenSize;
  final contentWidth = childSize.width; // actual rendered width
  final contentHeight = childSize.height; // actual rendered height

  final spaceBelow = screenSize.height - (targetOffset.dy + targetSize.height);
  final spaceAbove = targetOffset.dy;
  final spaceRight = screenSize.width - (targetOffset.dx + targetSize.width);
  final spaceLeft = targetOffset.dx;

  final requiredHeightSpace = contentHeight + offset;
  final requiredWidthSpace = contentWidth + offset;
  final extraWidthNeeded = contentWidth > targetSize.width ? contentWidth - targetSize.width : 0.0;
  final extraHeightNeeded = contentHeight > targetSize.height ? contentHeight - targetSize.height : 0.0;

  // For openOnSide = false (top/bottom)
  final canShowBelowTB = spaceBelow >= requiredHeightSpace;
  final canShowAboveTB = spaceAbove >= requiredHeightSpace;
  final canShowRightTB = spaceRight >= extraWidthNeeded;
  final canShowLeftTB = spaceLeft >= extraWidthNeeded;

  // For openOnSide = true (left/right)
  final canShowRightLR = spaceRight >= requiredWidthSpace;
  final canShowLeftLR = spaceLeft >= requiredWidthSpace;
  final canShowBelowLR = spaceBelow >= extraHeightNeeded;
  final canShowAboveLR = spaceAbove >= extraHeightNeeded;

  final (openUpward, openToRight, openOnSide, isCentered) = switch (alignment) {
    TPopupAlignment.bottomLeft => (
        canShowBelowTB ? false : (canShowAboveTB ? true : spaceAbove > spaceBelow),
        canShowRightTB ? true : (canShowLeftTB ? false : spaceRight > spaceLeft),
        false,
        false,
      ),
    TPopupAlignment.bottomRight => (
        canShowBelowTB ? false : (canShowAboveTB ? true : spaceAbove > spaceBelow),
        canShowLeftTB ? false : (canShowRightTB ? true : spaceRight > spaceLeft),
        false,
        false,
      ),
    TPopupAlignment.bottomCenter => (
        canShowBelowTB ? false : (canShowAboveTB ? true : spaceAbove > spaceBelow),
        true,
        false,
        true,
      ),
    TPopupAlignment.topLeft => (
        canShowAboveTB ? true : (canShowBelowTB ? false : spaceAbove > spaceBelow),
        canShowRightTB ? true : (canShowLeftTB ? false : spaceRight > spaceLeft),
        false,
        false,
      ),
    TPopupAlignment.topRight => (
        canShowAboveTB ? true : (canShowBelowTB ? false : spaceAbove > spaceBelow),
        canShowLeftTB ? false : (canShowRightTB ? true : spaceRight > spaceLeft),
        false,
        false,
      ),
    TPopupAlignment.topCenter => (
        canShowAboveTB ? true : (canShowBelowTB ? false : spaceAbove > spaceBelow),
        true,
        false,
        true,
      ),
    TPopupAlignment.rightTop => (
        canShowBelowLR ? false : (canShowAboveLR ? true : spaceAbove > spaceBelow),
        canShowRightLR ? true : (canShowLeftLR ? false : spaceRight > spaceLeft),
        true,
        false,
      ),
    TPopupAlignment.rightBottom => (
        canShowAboveLR ? true : (canShowBelowLR ? false : spaceAbove > spaceBelow),
        canShowRightLR ? true : (canShowLeftLR ? false : spaceRight > spaceLeft),
        true,
        false,
      ),
    TPopupAlignment.rightCenter => (
        canShowRightLR ? true : (canShowLeftLR ? false : spaceRight > spaceLeft),
        true,
        true,
        true,
      ),
    TPopupAlignment.leftTop => (
        canShowBelowLR ? false : (canShowAboveLR ? true : spaceAbove > spaceBelow),
        canShowLeftLR ? false : (canShowRightLR ? true : spaceRight > spaceLeft),
        true,
        false,
      ),
    TPopupAlignment.leftBottom => (
        canShowAboveLR ? true : (canShowBelowLR ? false : spaceAbove > spaceBelow),
        canShowLeftLR ? false : (canShowRightLR ? true : spaceRight > spaceLeft),
        true,
        false,
      ),
    TPopupAlignment.leftCenter => (
        canShowLeftLR ? false : (canShowRightLR ? true : spaceRight > spaceLeft),
        false,
        true,
        true,
      ),
  };

  double dx;
  double dy;

  if (openOnSide) {
    if (openToRight) {
      dx = targetOffset.dx + targetSize.width + offset;
    } else {
      dx = targetOffset.dx - contentWidth - offset;
    }

    if (isCentered) {
      dy = targetOffset.dy + (targetSize.height / 2) - (contentHeight / 2);
    } else if (openUpward) {
      dy = targetOffset.dy + targetSize.height - contentHeight;
    } else {
      dy = targetOffset.dy;
    }
  } else {
    if (openUpward) {
      dy = targetOffset.dy - contentHeight - offset;
    } else {
      dy = targetOffset.dy + targetSize.height + offset;
    }

    if (isCentered) {
      dx = targetOffset.dx + (targetSize.width / 2) - (contentWidth / 2);
    } else if (openToRight) {
      dx = targetOffset.dx;
    } else {
      dx = targetOffset.dx + targetSize.width - contentWidth;
    }
  }

  // Boundary check
  dx = dx.clamp(0.0, screenSize.width - contentWidth);
  dy = dy.clamp(0.0, screenSize.height - contentHeight);

  return Offset(dx, dy);
}