computeListPopupLayoutInfo function
MiuixListPopupLayoutInfo
computeListPopupLayoutInfo(
- BuildContext context, {
- required MiuixPopupAlign alignment,
- required MiuixPopupPositionProvider popupPositionProvider,
- required Rect parentBounds,
- required Size popupContentSize,
从窗口安全区、锚点与已测量内容计算 popup host 所需布局信息。
parentBounds 必须是窗口坐标。首次构建可传 Size.zero;此时返回预测
原点,待 MiuixListPopupContent.onPopupContentSizeChange 回报后重新计算。
Implementation
MiuixListPopupLayoutInfo computeListPopupLayoutInfo(
BuildContext context, {
required MiuixPopupAlign alignment,
required MiuixPopupPositionProvider popupPositionProvider,
required Rect parentBounds,
required Size popupContentSize,
}) {
final media = MediaQuery.of(context);
final direction = Directionality.of(context);
final containerSize = media.size;
final viewPadding = media.viewPadding;
final padding = media.padding;
final windowBounds = Rect.fromLTRB(
viewPadding.left,
padding.top,
containerSize.width - viewPadding.right,
containerSize.height - padding.bottom,
);
final popupMargin = popupPositionProvider.margins.resolve(direction);
final resolved = _resolvePopupAlign(alignment, direction);
final predictedX = switch (resolved) {
MiuixPopupAlign.end ||
MiuixPopupAlign.topEnd ||
MiuixPopupAlign.bottomEnd => parentBounds.right - popupMargin.right,
_ => parentBounds.left + popupMargin.left,
};
final predictedY = switch (resolved) {
MiuixPopupAlign.bottomStart ||
MiuixPopupAlign.bottomEnd => parentBounds.top - popupMargin.bottom,
_ => parentBounds.bottom + popupMargin.bottom,
};
final predictedOrigin = safeTransformOrigin(
predictedX / containerSize.width,
predictedY / containerSize.height,
);
if (popupContentSize == Size.zero) {
final rightAligned = switch (resolved) {
MiuixPopupAlign.end ||
MiuixPopupAlign.topEnd ||
MiuixPopupAlign.bottomEnd => true,
_ => false,
};
final position = MiuixPopupLayoutPosition(
showBelow: true,
showAbove: false,
isRightAligned: rightAligned,
);
return MiuixListPopupLayoutInfo(
windowBounds: windowBounds,
popupMargin: popupMargin,
calculatedOffset: Offset.zero,
effectiveTransformOrigin: predictedOrigin,
localTransformOrigin: Offset(rightAligned ? 1 : 0, 0),
popupLayoutPosition: position,
);
}
final offset = popupPositionProvider.calculatePosition(
anchorBounds: parentBounds,
windowBounds: windowBounds,
textDirection: direction,
popupContentSize: popupContentSize,
popupMargin: popupMargin,
alignment: alignment,
);
final popupCenterY = offset.dy + popupContentSize.height / 2;
final anchorCenterY = parentBounds.top + parentBounds.height / 2;
final showBelow = popupCenterY > anchorCenterY;
final showAbove = popupCenterY < anchorCenterY;
final distanceLeft = (offset.dx - parentBounds.left).abs();
final distanceRight =
(offset.dx + popupContentSize.width - parentBounds.right).abs();
final rightAligned = distanceRight < distanceLeft;
final position = MiuixPopupLayoutPosition(
showBelow: showBelow,
showAbove: showAbove,
isRightAligned: rightAligned,
);
final cornerX = rightAligned ? offset.dx + popupContentSize.width : offset.dx;
final cornerY = position.showMiddle
? offset.dy + popupContentSize.height / 2
: showBelow
? offset.dy
: offset.dy + popupContentSize.height;
final localY = position.showMiddle ? 0.5 : (showAbove ? 1.0 : 0.0);
return MiuixListPopupLayoutInfo(
windowBounds: windowBounds,
popupMargin: popupMargin,
calculatedOffset: offset,
effectiveTransformOrigin: safeTransformOrigin(
cornerX / containerSize.width,
cornerY / containerSize.height,
),
localTransformOrigin: Offset(rightAligned ? 1 : 0, localY),
popupLayoutPosition: position,
);
}