Unverified Commit d1185337 authored by Taufiq Rahman's avatar Taufiq Rahman Committed by GitHub

Feature: Allow `minLines` in `SelectableText` (#50750)

* Feature: allow minLines in SelectableText
parent 85ab331c
...@@ -205,6 +205,7 @@ class SelectableText extends StatefulWidget { ...@@ -205,6 +205,7 @@ class SelectableText extends StatefulWidget {
this.showCursor = false, this.showCursor = false,
this.autofocus = false, this.autofocus = false,
ToolbarOptions toolbarOptions, ToolbarOptions toolbarOptions,
this.minLines,
this.maxLines, this.maxLines,
this.cursorWidth = 2.0, this.cursorWidth = 2.0,
this.cursorRadius, this.cursorRadius,
...@@ -218,6 +219,11 @@ class SelectableText extends StatefulWidget { ...@@ -218,6 +219,11 @@ class SelectableText extends StatefulWidget {
assert(autofocus != null), assert(autofocus != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(maxLines == null || maxLines > 0), assert(maxLines == null || maxLines > 0),
assert(minLines == null || minLines > 0),
assert(
(maxLines == null) || (minLines == null) || (maxLines >= minLines),
'minLines can\'t be greater than maxLines',
),
assert( assert(
data != null, data != null,
'A non-null String must be provided to a SelectableText widget.', 'A non-null String must be provided to a SelectableText widget.',
...@@ -248,6 +254,7 @@ class SelectableText extends StatefulWidget { ...@@ -248,6 +254,7 @@ class SelectableText extends StatefulWidget {
this.showCursor = false, this.showCursor = false,
this.autofocus = false, this.autofocus = false,
ToolbarOptions toolbarOptions, ToolbarOptions toolbarOptions,
this.minLines,
this.maxLines, this.maxLines,
this.cursorWidth = 2.0, this.cursorWidth = 2.0,
this.cursorRadius, this.cursorRadius,
...@@ -261,6 +268,11 @@ class SelectableText extends StatefulWidget { ...@@ -261,6 +268,11 @@ class SelectableText extends StatefulWidget {
assert(autofocus != null), assert(autofocus != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(maxLines == null || maxLines > 0), assert(maxLines == null || maxLines > 0),
assert(minLines == null || minLines > 0),
assert(
(maxLines == null) || (minLines == null) || (maxLines >= minLines),
'minLines can\'t be greater than maxLines',
),
assert( assert(
textSpan != null, textSpan != null,
'A non-null TextSpan must be provided to a SelectableText.rich widget.', 'A non-null TextSpan must be provided to a SelectableText.rich widget.',
...@@ -329,6 +341,9 @@ class SelectableText extends StatefulWidget { ...@@ -329,6 +341,9 @@ class SelectableText extends StatefulWidget {
/// {@macro flutter.widgets.editableText.autofocus} /// {@macro flutter.widgets.editableText.autofocus}
final bool autofocus; final bool autofocus;
/// {@macro flutter.widgets.editableText.minLines}
final int minLines;
/// {@macro flutter.widgets.editableText.maxLines} /// {@macro flutter.widgets.editableText.maxLines}
final int maxLines; final int maxLines;
...@@ -398,6 +413,7 @@ class SelectableText extends StatefulWidget { ...@@ -398,6 +413,7 @@ class SelectableText extends StatefulWidget {
properties.add(DiagnosticsProperty<TextStyle>('style', style, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('style', style, defaultValue: null));
properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
properties.add(DiagnosticsProperty<bool>('showCursor', showCursor, defaultValue: false)); properties.add(DiagnosticsProperty<bool>('showCursor', showCursor, defaultValue: false));
properties.add(IntProperty('minLines', minLines, defaultValue: null));
properties.add(IntProperty('maxLines', maxLines, defaultValue: null)); properties.add(IntProperty('maxLines', maxLines, defaultValue: null));
properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null)); properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null));
properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
...@@ -582,6 +598,7 @@ class _SelectableTextState extends State<SelectableText> with AutomaticKeepAlive ...@@ -582,6 +598,7 @@ class _SelectableTextState extends State<SelectableText> with AutomaticKeepAlive
autofocus: widget.autofocus, autofocus: widget.autofocus,
forceLine: false, forceLine: false,
toolbarOptions: widget.toolbarOptions, toolbarOptions: widget.toolbarOptions,
minLines: widget.minLines,
maxLines: widget.maxLines ?? defaultTextStyle.maxLines, maxLines: widget.maxLines ?? defaultTextStyle.maxLines,
selectionColor: themeData.textSelectionColor, selectionColor: themeData.textSelectionColor,
selectionControls: widget.selectionEnabled ? textSelectionControls : null, selectionControls: widget.selectionEnabled ? textSelectionControls : null,
......
...@@ -177,12 +177,17 @@ void main() { ...@@ -177,12 +177,17 @@ void main() {
debugResetSemanticsIdCounter(); debugResetSemanticsIdCounter();
}); });
Widget selectableTextBuilder({String text = '', int maxLines = 1}) { Widget selectableTextBuilder({
String text = '',
int maxLines = 1,
int minLines,
}) {
return boilerplate( return boilerplate(
child: SelectableText( child: SelectableText(
text, text,
style: const TextStyle(color: Colors.black, fontSize: 34.0), style: const TextStyle(color: Colors.black, fontSize: 34.0),
maxLines: maxLines, maxLines: maxLines,
minLines: minLines,
), ),
); );
} }
...@@ -1155,6 +1160,41 @@ void main() { ...@@ -1155,6 +1160,41 @@ void main() {
expect(inputBox.hitTest(BoxHitTestResult(), position: inputBox.globalToLocal(newFourthPos)), isFalse); expect(inputBox.hitTest(BoxHitTestResult(), position: inputBox.globalToLocal(newFourthPos)), isFalse);
}); });
testWidgets('minLines cannot be greater than maxLines', (WidgetTester tester) async {
try {
await tester.pumpWidget(
overlay(
child: Container(
width: 300.0,
child: SelectableText(
'abcd',
minLines: 4,
maxLines: 3,
),
),
),
);
} on AssertionError catch (e) {
expect(e.toString(), contains("minLines can't be greater than maxLines"));
return;
}
fail('An assert should be triggered when minLines is greater than maxLines');
});
testWidgets('Selectable height with minLine', (WidgetTester tester) async {
await tester.pumpWidget(selectableTextBuilder());
RenderBox findTextBox() => tester.renderObject(find.byType(SelectableText));
final RenderBox textBox = findTextBox();
final Size emptyInputSize = textBox.size;
// Even if the text is a one liner, minimum height of SelectableText will determined by minLines
await tester.pumpWidget(selectableTextBuilder(text: 'No wrapping here.', minLines: 2, maxLines: 3));
expect(findTextBox(), equals(textBox));
expect(textBox.size.height, emptyInputSize.height * 2);
});
testWidgets('Can align to center', (WidgetTester tester) async { testWidgets('Can align to center', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
overlay( overlay(
...@@ -3189,6 +3229,7 @@ void main() { ...@@ -3189,6 +3229,7 @@ void main() {
textScaleFactor: 1.0, textScaleFactor: 1.0,
autofocus: true, autofocus: true,
showCursor: true, showCursor: true,
minLines: 2,
maxLines: 10, maxLines: 10,
cursorWidth: 1.0, cursorWidth: 1.0,
cursorRadius: Radius.zero, cursorRadius: Radius.zero,
...@@ -3206,6 +3247,7 @@ void main() { ...@@ -3206,6 +3247,7 @@ void main() {
'style: TextStyle(inherit: true, color: Color(0xff00ff00))', 'style: TextStyle(inherit: true, color: Color(0xff00ff00))',
'autofocus: true', 'autofocus: true',
'showCursor: true', 'showCursor: true',
'minLines: 2',
'maxLines: 10', 'maxLines: 10',
'textAlign: end', 'textAlign: end',
'textDirection: ltr', 'textDirection: ltr',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment