Feat: Add opportunity to change CupertinoTextField suffix alignment (#154601)

Fixes #152482
This commit is contained in:
AntØn UstinØff 2024-10-01 19:13:09 +04:00 committed by GitHub
parent b05246d305
commit 6bba08cbcc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 100 additions and 21 deletions

View File

@ -239,6 +239,7 @@ class CupertinoTextField extends StatefulWidget {
this.prefixMode = OverlayVisibilityMode.always, this.prefixMode = OverlayVisibilityMode.always,
this.suffix, this.suffix,
this.suffixMode = OverlayVisibilityMode.always, this.suffixMode = OverlayVisibilityMode.always,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.clearButtonMode = OverlayVisibilityMode.never, this.clearButtonMode = OverlayVisibilityMode.never,
this.clearButtonSemanticLabel, this.clearButtonSemanticLabel,
TextInputType? keyboardType, TextInputType? keyboardType,
@ -367,6 +368,7 @@ class CupertinoTextField extends StatefulWidget {
this.prefixMode = OverlayVisibilityMode.always, this.prefixMode = OverlayVisibilityMode.always,
this.suffix, this.suffix,
this.suffixMode = OverlayVisibilityMode.always, this.suffixMode = OverlayVisibilityMode.always,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.clearButtonMode = OverlayVisibilityMode.never, this.clearButtonMode = OverlayVisibilityMode.never,
this.clearButtonSemanticLabel, this.clearButtonSemanticLabel,
TextInputType? keyboardType, TextInputType? keyboardType,
@ -516,6 +518,13 @@ class CupertinoTextField extends StatefulWidget {
/// Has no effect when [suffix] is null. /// Has no effect when [suffix] is null.
final OverlayVisibilityMode suffixMode; final OverlayVisibilityMode suffixMode;
/// Controls the vertical alignment of the [prefix] and the [suffix] widget in relation to content.
///
/// Defaults to [CrossAxisAlignment.center].
///
/// Has no effect when both the [prefix] and [suffix] are null.
final CrossAxisAlignment crossAxisAlignment;
/// Show an iOS-style clear button to clear the current text entry. /// Show an iOS-style clear button to clear the current text entry.
/// ///
/// Can be made to appear depending on various text states of the /// Can be made to appear depending on various text states of the
@ -1213,28 +1222,31 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
(true, true) => widget.suffix ?? _buildClearButton(), (true, true) => widget.suffix ?? _buildClearButton(),
(false, true) => _buildClearButton(), (false, true) => _buildClearButton(),
}; };
return Row(children: <Widget>[ return Row(
// Insert a prefix at the front if the prefix visibility mode matches crossAxisAlignment: widget.crossAxisAlignment,
// the current text state. children: <Widget>[
if (prefixWidget != null) prefixWidget, // Insert a prefix at the front if the prefix visibility mode matches
// In the middle part, stack the placeholder on top of the main EditableText // the current text state.
// if needed. if (prefixWidget != null) prefixWidget,
Expanded( // In the middle part, stack the placeholder on top of the main EditableText
child: Stack( // if needed.
// Ideally this should be baseline aligned. However that comes at Expanded(
// the cost of the ability to compute the intrinsic dimensions of child: Stack(
// this widget. // Ideally this should be baseline aligned. However that comes at
// See also https://github.com/flutter/flutter/issues/13715. // the cost of the ability to compute the intrinsic dimensions of
alignment: AlignmentDirectional.center, // this widget.
textDirection: widget.textDirection, // See also https://github.com/flutter/flutter/issues/13715.
children: <Widget>[ alignment: AlignmentDirectional.center,
if (placeholder != null) placeholder, textDirection: widget.textDirection,
editableText, children: <Widget>[
], if (placeholder != null) placeholder,
editableText,
],
),
), ),
), if (suffixWidget != null) suffixWidget,
if (suffixWidget != null) suffixWidget ],
]); );
}, },
); );
} }

View File

@ -8067,6 +8067,73 @@ void main() {
); );
}); });
testWidgets(
'CrossAxisAlignment start positions the prefix and suffix at the top of the field',
(WidgetTester tester) async {
await tester.pumpWidget(
const CupertinoApp(
home: Center(
child: CupertinoTextField(
padding: EdgeInsets.zero, // Preventing delta position.dy
prefix: Icon(CupertinoIcons.add),
suffix: Icon(CupertinoIcons.clear),
crossAxisAlignment: CrossAxisAlignment.start,
),
),
),
);
final CupertinoTextField cupertinoTextField = tester.widget<CupertinoTextField>(
find.byType(CupertinoTextField),
);
expect(find.widgetWithIcon(CupertinoTextField, CupertinoIcons.clear), findsOneWidget);
expect(find.widgetWithIcon(CupertinoTextField, CupertinoIcons.add), findsOneWidget);
expect(cupertinoTextField.crossAxisAlignment, CrossAxisAlignment.start);
final double editableDy = tester.getTopLeft(find.byType(EditableText)).dy;
final double prefixDy = tester.getTopLeft(find.byIcon(CupertinoIcons.add)).dy;
final double suffixDy = tester.getTopLeft(find.byIcon(CupertinoIcons.clear)).dy;
expect(prefixDy, editableDy);
expect(suffixDy, editableDy);
},
);
testWidgets(
'CrossAxisAlignment end positions the prefix and suffix at the bottom of the field',
(WidgetTester tester) async {
await tester.pumpWidget(
const CupertinoApp(
home: Center(
child: CupertinoTextField(
padding: EdgeInsets.zero, // Preventing delta position.dy
prefix: SizedBox.square(dimension: 48, child: Icon(CupertinoIcons.add)),
suffix: SizedBox.square(dimension: 48, child: Icon(CupertinoIcons.clear)),
crossAxisAlignment: CrossAxisAlignment.end,
),
),
),
);
final CupertinoTextField cupertinoTextField = tester.widget<CupertinoTextField>(
find.byType(CupertinoTextField),
);
expect(find.widgetWithIcon(CupertinoTextField, CupertinoIcons.clear), findsOneWidget);
expect(find.widgetWithIcon(CupertinoTextField, CupertinoIcons.add), findsOneWidget);
expect(cupertinoTextField.crossAxisAlignment, CrossAxisAlignment.end);
final double editableDy = tester.getTopLeft(find.byType(EditableText)).dy;
final double prefixDy = tester.getTopLeft(find.byIcon(CupertinoIcons.add)).dy;
final double suffixDy = tester.getTopLeft(find.byIcon(CupertinoIcons.clear)).dy;
expect(prefixDy, lessThan(editableDy));
expect(suffixDy, lessThan(editableDy));
},
);
testWidgets('text selection style 1', (WidgetTester tester) async { testWidgets('text selection style 1', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'Atwater Peel Sherbrooke Bonaventure\nhi\nwassssup!', text: 'Atwater Peel Sherbrooke Bonaventure\nhi\nwassssup!',