Fix: Submenu anchor misaligned with child panel in web (Resolved #151081) (#151294)

Fix: Submenu anchor misaligned with child panel in web (Resolved #151081)

- The issue comes from different in calculating the position of the menu in web and mobile.
- The calculation is currently base on function `getPositionForChild()` inside `_MenuLayout` in `menu_anchor.dart`, which base on the `anchorRect`
- The calculation of `anchorRect` is from `upperLeft` and `bottomRight`
- `upperLeft` is result of `localToGlobal()` function, which take the `point` arguments to be the base line. Right now, `point` is refer to `Offset.zero`, but it should not be Offset.zero since we having `densityAdjustment`, which is different between web and mobile
- Change `point` from `Offset.zero` to `Offset(dx, -dy)` should fix the error. Use `dx` instead of `-dx` since `dx` already be recalculated refer to the above comment on `densityAdjustment`.
Before:
![Screenshot 2024-07-03 at 10 28 51](https://github.com/flutter/flutter/assets/57765714/cd634ce5-8699-49ee-806f-435cbbca81a4)
After:
![Screenshot 2024-07-03 at 10 28 21](https://github.com/flutter/flutter/assets/57765714/81119996-b3e5-4e45-b44b-11fff8521998)

Issue: https://github.com/flutter/flutter/issues/151081
This commit is contained in:
Bui Anh Viet 2024-07-12 02:25:18 +07:00 committed by GitHub
parent ceced3984f
commit bc3d2feb9c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 12 additions and 12 deletions

View File

@ -3529,12 +3529,6 @@ class _Submenu extends StatelessWidget {
final VisualDensity visualDensity =
effectiveValue((MenuStyle? style) => style?.visualDensity) ?? Theme.of(context).visualDensity;
final AlignmentGeometry alignment = effectiveValue((MenuStyle? style) => style?.alignment)!;
final BuildContext anchorContext = anchor._anchorKey.currentContext!;
final RenderBox overlay = Overlay.of(anchorContext).context.findRenderObject()! as RenderBox;
final RenderBox anchorBox = anchorContext.findRenderObject()! as RenderBox;
final Offset upperLeft = anchorBox.localToGlobal(Offset.zero, ancestor: overlay);
final Offset bottomRight = anchorBox.localToGlobal(anchorBox.paintBounds.bottomRight, ancestor: overlay);
final Rect anchorRect = Rect.fromPoints(upperLeft, bottomRight);
final EdgeInsetsGeometry padding =
resolve<EdgeInsetsGeometry?>((MenuStyle? style) => style?.padding) ?? EdgeInsets.zero;
final Offset densityAdjustment = visualDensity.baseSizeAdjustment;
@ -3547,6 +3541,12 @@ class _Submenu extends StatelessWidget {
final EdgeInsetsGeometry resolvedPadding = padding
.add(EdgeInsets.fromLTRB(dx, dy, dx, dy))
.clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity);
final BuildContext anchorContext = anchor._anchorKey.currentContext!;
final RenderBox overlay = Overlay.of(anchorContext).context.findRenderObject()! as RenderBox;
final RenderBox anchorBox = anchorContext.findRenderObject()! as RenderBox;
final Offset upperLeft = anchorBox.localToGlobal(Offset(dx, -dy), ancestor: overlay);
final Offset bottomRight = anchorBox.localToGlobal(anchorBox.paintBounds.bottomRight, ancestor: overlay);
final Rect anchorRect = Rect.fromPoints(upperLeft, bottomRight);
return Theme(
data: Theme.of(context).copyWith(

View File

@ -256,13 +256,13 @@ void main() {
expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(105.0, 0.0, 695.0, 72.0)));
expect(
tester.getRect(find.widgetWithText(MenuItemButton, TestMenu.subMenu10.label)),
equals(const Rect.fromLTRB(249.0, 80.0, 483.0, 136.0)),
equals(const Rect.fromLTRB(257.0, 80.0, 491.0, 136.0)),
);
expect(
tester.getRect(
find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).at(1),
),
equals(const Rect.fromLTRB(241.0, 64.0, 491.0, 264.0)),
equals(const Rect.fromLTRB(249.0, 64.0, 499.0, 264.0)),
);
});
@ -3181,7 +3181,7 @@ void main() {
equals(const <Rect>[
Rect.fromLTRB(161.0, 0.0, 639.0, 40.0),
Rect.fromLTRB(265.0, 40.0, 467.0, 160.0),
Rect.fromLTRB(467.0, 72.0, 707.0, 232.0),
Rect.fromLTRB(467.0, 80.0, 707.0, 240.0),
]),
);
});
@ -3197,7 +3197,7 @@ void main() {
equals(const <Rect>[
Rect.fromLTRB(161.0, 0.0, 639.0, 40.0),
Rect.fromLTRB(333.0, 40.0, 535.0, 160.0),
Rect.fromLTRB(93.0, 72.0, 333.0, 232.0),
Rect.fromLTRB(93.0, 80.0, 333.0, 240.0),
]),
);
});

View File

@ -280,11 +280,11 @@ void main() {
expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(228.0, 0.0, 572.0, 48.0)));
expect(
tester.getRect(find.text(TestMenu.subMenu10.label)),
equals(const Rect.fromLTRB(366.0, 68.0, 559.0, 82.0)),
equals(const Rect.fromLTRB(372.0, 68.0, 565.0, 82.0)),
);
expect(
tester.getRect(find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).at(1)),
equals(const Rect.fromLTRB(346.0, 48.0, 579.0, 186.0)),
equals(const Rect.fromLTRB(352.0, 48.0, 585.0, 186.0)),
);
});
});