mirror of
https://github.com/flutter/flutter
synced 2024-08-24 18:36:03 +00:00
Horizontally expand text selection toolbar buttons in overflow menu (#144391)
## Description This PR expands the items displayed in the overflow menu of a `TextSelectionToolbar` making buttons clickable in the blank area. | Before | After | |--------|--------| | Each item has its own width | All items expand horizontally | | ![Capture dâeÌcran 2024-02-29 aÌ 14 43 57](https://github.com/flutter/flutter/assets/840911/f7379eef-9185-4cc4-bf14-e4c916c432b1) | ![Capture dâeÌcran 2024-02-29 aÌ 14 40 47](https://github.com/flutter/flutter/assets/840911/bff272cd-9fe2-4f07-adaf-61edef03d26e) | ## Related Issue Fixes https://github.com/flutter/flutter/issues/144089. ## Tests Adds 1 tests.
This commit is contained in:
parent
263ffe5f04
commit
8a312cd01a
|
@ -262,6 +262,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
|
||||||
buttons.add(TextSelectionToolbarTextButton(
|
buttons.add(TextSelectionToolbarTextButton(
|
||||||
padding: TextSelectionToolbarTextButton.getPadding(i, buttonItems.length),
|
padding: TextSelectionToolbarTextButton.getPadding(i, buttonItems.length),
|
||||||
onPressed: buttonItem.onPressed,
|
onPressed: buttonItem.onPressed,
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: Text(getButtonLabel(context, buttonItem)),
|
child: Text(getButtonLabel(context, buttonItem)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,6 +267,7 @@ class _TextSelectionControlsToolbarState extends State<_TextSelectionControlsToo
|
||||||
children: itemDatas.asMap().entries.map((MapEntry<int, _TextSelectionToolbarItemData> entry) {
|
children: itemDatas.asMap().entries.map((MapEntry<int, _TextSelectionToolbarItemData> entry) {
|
||||||
return TextSelectionToolbarTextButton(
|
return TextSelectionToolbarTextButton(
|
||||||
padding: TextSelectionToolbarTextButton.getPadding(entry.key, itemDatas.length),
|
padding: TextSelectionToolbarTextButton.getPadding(entry.key, itemDatas.length),
|
||||||
|
alignment: AlignmentDirectional.centerStart,
|
||||||
onPressed: entry.value.onPressed,
|
onPressed: entry.value.onPressed,
|
||||||
child: Text(entry.value.label),
|
child: Text(entry.value.label),
|
||||||
);
|
);
|
||||||
|
|
|
@ -569,6 +569,40 @@ class _RenderTextSelectionToolbarItemsLayout extends RenderBox with ContainerRen
|
||||||
size = nextSize;
|
size = nextSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Horizontally expand the children when the menu overflows so they can react to
|
||||||
|
// pointer events into their whole area.
|
||||||
|
void _resizeChildrenWhenOverflow() {
|
||||||
|
if (!overflowOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final RenderBox navButton = firstChild!;
|
||||||
|
int i = -1;
|
||||||
|
|
||||||
|
visitChildren((RenderObject renderObjectChild) {
|
||||||
|
final RenderBox child = renderObjectChild as RenderBox;
|
||||||
|
final ToolbarItemsParentData childParentData = child.parentData! as ToolbarItemsParentData;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// Ignore the navigation button.
|
||||||
|
if (renderObjectChild == navButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is no need to update children that won't be painted.
|
||||||
|
if (!_shouldPaintChild(renderObjectChild, i)) {
|
||||||
|
childParentData.shouldPaint = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.layout(
|
||||||
|
BoxConstraints.tightFor(width: size.width),
|
||||||
|
parentUsesSize: true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
_lastIndexThatFits = -1;
|
_lastIndexThatFits = -1;
|
||||||
|
@ -579,6 +613,7 @@ class _RenderTextSelectionToolbarItemsLayout extends RenderBox with ContainerRen
|
||||||
|
|
||||||
_layoutChildren();
|
_layoutChildren();
|
||||||
_placeChildren();
|
_placeChildren();
|
||||||
|
_resizeChildrenWhenOverflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -291,4 +291,64 @@ void main() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testWidgets('Overflowed menu expands children horizontally', (WidgetTester tester) async {
|
||||||
|
// Regression test for https://github.com/flutter/flutter/issues/144089.
|
||||||
|
late StateSetter setState;
|
||||||
|
final List<Widget> children = List<Widget>.generate(7, (int i) => const TestBox());
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setter) {
|
||||||
|
setState = setter;
|
||||||
|
return TextSelectionToolbar(
|
||||||
|
anchorAbove: const Offset(50.0, 100.0),
|
||||||
|
anchorBelow: const Offset(50.0, 200.0),
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// All children fit on the screen, so they are all rendered.
|
||||||
|
expect(find.byType(TestBox), findsNWidgets(children.length));
|
||||||
|
expect(findOverflowButton(), findsNothing);
|
||||||
|
|
||||||
|
const String short = 'Short';
|
||||||
|
const String medium = 'Medium length';
|
||||||
|
const String long = 'Long label in the overflow menu';
|
||||||
|
|
||||||
|
// Adding several children makes the menu overflow.
|
||||||
|
setState(() {
|
||||||
|
children.addAll(const <Text>[
|
||||||
|
Text(short),
|
||||||
|
Text(medium),
|
||||||
|
Text(long),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(findOverflowButton(), findsOneWidget);
|
||||||
|
|
||||||
|
// Tap the overflow button to show the overflow menu.
|
||||||
|
await tester.tap(findOverflowButton());
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.byType(TestBox), findsNothing);
|
||||||
|
expect(find.byType(Text), findsNWidgets(3));
|
||||||
|
expect(findOverflowButton(), findsOneWidget);
|
||||||
|
|
||||||
|
Finder findToolbarContainer() {
|
||||||
|
return find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionToolbarContainer');
|
||||||
|
}
|
||||||
|
expect(findToolbarContainer(), findsAtLeastNWidgets(1));
|
||||||
|
|
||||||
|
// Buttons have their width set to the container width.
|
||||||
|
final double overflowMenuWidth = tester.getRect(findToolbarContainer()).width;
|
||||||
|
expect(tester.getRect(find.text(long)).width, overflowMenuWidth);
|
||||||
|
expect(tester.getRect(find.text(medium)).width, overflowMenuWidth);
|
||||||
|
expect(tester.getRect(find.text(short)).width, overflowMenuWidth);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue