Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
d74a5883
Commit
d74a5883
authored
Jun 13, 2017
by
Ian Hickson
Committed by
GitHub
Jun 13, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow multi-line text fields with no line limit (#10576)
parent
db75aa76
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
219 additions
and
53 deletions
+219
-53
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+18
-3
text_form_field.dart
packages/flutter/lib/src/material/text_form_field.dart
+7
-2
text_painter.dart
packages/flutter/lib/src/painting/text_painter.dart
+5
-0
text_style.dart
packages/flutter/lib/src/painting/text_style.dart
+7
-1
editable.dart
packages/flutter/lib/src/rendering/editable.dart
+47
-16
paragraph.dart
packages/flutter/lib/src/rendering/paragraph.dart
+15
-5
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+9
-1
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+13
-5
text.dart
packages/flutter/lib/src/widgets/text.dart
+34
-2
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+32
-16
paragraph_test.dart
packages/flutter/test/rendering/paragraph_test.dart
+32
-2
No files found.
packages/flutter/lib/src/material/text_field.dart
View file @
d74a5883
...
...
@@ -62,6 +62,12 @@ class TextField extends StatefulWidget {
/// To remove the decoration entirely (including the extra padding introduced
/// by the decoration to save space for the labels), set the [decoration] to
/// null.
///
/// The [maxLines] property can be set to null to remove the restriction on
/// the number of lines. By default, it is 1, meaning this is a single-line
/// text field. If it is not null, it must be greater than zero.
///
/// The [keyboardType], [autofocus], and [obscureText] arguments must not be null.
const
TextField
({
Key
key
,
this
.
controller
,
...
...
@@ -76,7 +82,11 @@ class TextField extends StatefulWidget {
this
.
onChanged
,
this
.
onSubmitted
,
this
.
inputFormatters
,
})
:
super
(
key:
key
);
})
:
assert
(
keyboardType
!=
null
),
assert
(
autofocus
!=
null
),
assert
(
obscureText
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
super
(
key:
key
);
/// Controls the text being edited.
///
...
...
@@ -98,6 +108,8 @@ class TextField extends StatefulWidget {
final
InputDecoration
decoration
;
/// The type of keyboard to use for editing the text.
///
/// Defaults to [TextInputType.text]. Cannot be null.
final
TextInputType
keyboardType
;
/// The style to use for the text being edited.
...
...
@@ -116,7 +128,7 @@ class TextField extends StatefulWidget {
/// If true, the keyboard will open as soon as this text field obtains focus.
/// Otherwise, the keyboard is only shown after the user taps the text field.
///
/// Defaults to false.
/// Defaults to false.
Cannot be null.
// See https://github.com/flutter/flutter/issues/7035 for the rationale for this
// keyboard behavior.
final
bool
autofocus
;
...
...
@@ -126,13 +138,16 @@ class TextField extends StatefulWidget {
/// When this is set to true, all the characters in the text field are
/// replaced by U+2022 BULLET characters (•).
///
/// Defaults to false.
/// Defaults to false.
Cannot be null.
final
bool
obscureText
;
/// The maximum number of lines for the text to span, wrapping if necessary.
///
/// If this is 1 (the default), the text will not wrap, but will scroll
/// horizontally instead.
///
/// If this is null, there is no limit to the number of lines. If it is not
/// null, the value must be greater than zero.
final
int
maxLines
;
/// Called when the text being edited changes.
...
...
packages/flutter/lib/src/material/text_form_field.dart
View file @
d74a5883
...
...
@@ -30,7 +30,8 @@ import 'text_field.dart';
class
TextFormField
extends
FormField
<
String
>
{
/// Creates a [FormField] that contains a [TextField].
///
/// For a documentation about the various parameters, see [TextField].
/// For documentation about the various parameters, see the [TextField] class
/// and [new TextField], the constructor.
TextFormField
({
Key
key
,
TextEditingController
controller
,
...
...
@@ -44,7 +45,11 @@ class TextFormField extends FormField<String> {
FormFieldSetter
<
String
>
onSaved
,
FormFieldValidator
<
String
>
validator
,
List
<
TextInputFormatter
>
inputFormatters
,
})
:
super
(
})
:
assert
(
keyboardType
!=
null
),
assert
(
autofocus
!=
null
),
assert
(
obscureText
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
super
(
key:
key
,
initialValue:
controller
!=
null
?
controller
.
value
.
text
:
''
,
onSaved:
onSaved
,
...
...
packages/flutter/lib/src/painting/text_painter.dart
View file @
d74a5883
...
...
@@ -35,6 +35,8 @@ class TextPainter {
///
/// The text argument is optional but [text] must be non-null before calling
/// [layout].
///
/// The [maxLines] property, if non-null, must be greater than zero.
TextPainter
({
TextSpan
text
,
TextAlign
textAlign
,
...
...
@@ -43,6 +45,7 @@ class TextPainter {
String
ellipsis
,
})
:
assert
(
text
==
null
||
text
.
debugAssertIsValid
()),
assert
(
textScaleFactor
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
_text
=
text
,
_textAlign
=
textAlign
,
_textScaleFactor
=
textScaleFactor
,
...
...
@@ -134,7 +137,9 @@ class TextPainter {
/// After this is set, you must call [layout] before the next call to [paint].
int
get
maxLines
=>
_maxLines
;
int
_maxLines
;
/// The value may be null. If it is not null, then it must be greater than zero.
set
maxLines
(
int
value
)
{
assert
(
value
==
null
||
value
>
0
);
if
(
_maxLines
==
value
)
return
;
_maxLines
=
value
;
...
...
packages/flutter/lib/src/painting/text_style.dart
View file @
d74a5883
...
...
@@ -234,12 +234,18 @@ class TextStyle {
}
/// The style information for paragraphs, encoded for use by `dart:ui`.
///
/// The `textScaleFactor` argument must not be null. If omitted, it defaults
/// to 1.0. The other arguments may be null. The `maxLines` argument, if
/// specified and non-null, must be greater than zero.
ui
.
ParagraphStyle
getParagraphStyle
({
TextAlign
textAlign
,
double
textScaleFactor:
1.0
,
String
ellipsis
,
int
maxLines
,
})
{
})
{
assert
(
textScaleFactor
!=
null
);
assert
(
maxLines
==
null
||
maxLines
>
0
);
return
new
ui
.
ParagraphStyle
(
textAlign:
textAlign
,
fontWeight:
fontWeight
,
...
...
packages/flutter/lib/src/rendering/editable.dart
View file @
d74a5883
...
...
@@ -84,6 +84,15 @@ class TextSelectionPoint {
/// responsibility of higher layers and not handled by this object.
class
RenderEditable
extends
RenderBox
{
/// Creates a render object that implements the visual aspects of a text field.
///
/// If [showCursor] is not specified, then it defaults to hiding the cursor.
///
/// The [maxLines] property can be set to null to remove the restriction on
/// the number of lines. By default, it is 1, meaning this is a single-line
/// text field. If it is not null, it must be greater than zero.
///
/// The [offset] is required and must not be null. You can use [new
/// ViewportOffset.zero] if you have no need for scrolling.
RenderEditable
({
TextSpan
text
,
TextAlign
textAlign
,
...
...
@@ -96,7 +105,7 @@ class RenderEditable extends RenderBox {
@required
ViewportOffset
offset
,
this
.
onSelectionChanged
,
this
.
onCaretChanged
,
})
:
assert
(
maxLines
!=
null
),
})
:
assert
(
maxLines
==
null
||
maxLines
>
0
),
assert
(
textScaleFactor
!=
null
),
assert
(
offset
!=
null
),
_textPainter
=
new
TextPainter
(
text:
text
,
textAlign:
textAlign
,
textScaleFactor:
textScaleFactor
),
...
...
@@ -180,13 +189,21 @@ class RenderEditable extends RenderBox {
}
/// The maximum number of lines for the text to span, wrapping if necessary.
///
/// If this is 1 (the default), the text will not wrap, but will extend
/// indefinitely instead.
///
/// If this is null, there is no limit to the number of lines.
///
/// When this is not null, the intrinsic height of the render object is the
/// height of one line of text multiplied by this value. In other words, this
/// also controls the height of the actual editing widget.
int
get
maxLines
=>
_maxLines
;
int
_maxLines
;
/// The value may be null. If it is not null, then it must be greater than zero.
set
maxLines
(
int
value
)
{
assert
(
value
!=
null
);
if
(
_
maxLines
==
value
)
assert
(
value
==
null
||
value
>
0
);
if
(
maxLines
==
value
)
return
;
_maxLines
=
value
;
markNeedsTextLayout
();
...
...
@@ -261,7 +278,7 @@ class RenderEditable extends RenderBox {
super
.
detach
();
}
bool
get
_isMultiline
=>
maxLines
>
1
;
bool
get
_isMultiline
=>
maxLines
!=
1
;
Axis
get
_viewportAxis
=>
_isMultiline
?
Axis
.
vertical
:
Axis
.
horizontal
;
...
...
@@ -359,14 +376,30 @@ class RenderEditable extends RenderBox {
// This does not required the layout to be updated.
double
get
_preferredLineHeight
=>
_textPainter
.
preferredLineHeight
;
double
_preferredHeight
(
double
width
)
{
if
(
maxLines
!=
null
)
return
_preferredLineHeight
*
maxLines
;
if
(
width
==
double
.
INFINITY
)
{
final
String
text
=
_textPainter
.
text
.
toPlainText
();
int
lines
=
1
;
for
(
int
index
=
0
;
index
<
text
.
length
;
index
+=
1
)
{
if
(
text
.
codeUnitAt
(
index
)
==
0x0A
)
// count explicit line breaks
lines
+=
1
;
}
return
_preferredLineHeight
*
lines
;
}
_layoutText
(
width
);
return
math
.
max
(
_preferredLineHeight
,
_textPainter
.
height
);
}
@override
double
computeMinIntrinsicHeight
(
double
width
)
{
return
_preferred
LineHeight
;
return
_preferred
Height
(
width
)
;
}
@override
double
computeMaxIntrinsicHeight
(
double
width
)
{
return
_preferred
LineHeight
*
maxLines
;
return
_preferred
Height
(
width
)
;
}
@override
...
...
@@ -434,7 +467,7 @@ class RenderEditable extends RenderBox {
return
;
final
double
caretMargin
=
_kCaretGap
+
_kCaretWidth
;
final
double
availableWidth
=
math
.
max
(
0.0
,
constraintWidth
-
caretMargin
);
final
double
maxWidth
=
_
maxLines
>
1
?
availableWidth
:
double
.
INFINITY
;
final
double
maxWidth
=
_
isMultiline
?
availableWidth
:
double
.
INFINITY
;
_textPainter
.
layout
(
minWidth:
availableWidth
,
maxWidth:
maxWidth
);
_textLayoutLastWidth
=
constraintWidth
;
}
...
...
@@ -444,9 +477,7 @@ class RenderEditable extends RenderBox {
_layoutText
(
constraints
.
maxWidth
);
_caretPrototype
=
new
Rect
.
fromLTWH
(
0.0
,
_kCaretHeightOffset
,
_kCaretWidth
,
_preferredLineHeight
-
2.0
*
_kCaretHeightOffset
);
_selectionRects
=
null
;
size
=
new
Size
(
constraints
.
maxWidth
,
constraints
.
constrainHeight
(
_textPainter
.
height
.
clamp
(
_preferredLineHeight
,
_preferredLineHeight
*
_maxLines
)
));
size
=
new
Size
(
constraints
.
maxWidth
,
constraints
.
constrainHeight
(
_preferredHeight
(
constraints
.
maxWidth
)));
final
Size
contentSize
=
new
Size
(
_textPainter
.
width
+
_kCaretGap
+
_kCaretWidth
,
_textPainter
.
height
);
final
double
_maxScrollExtent
=
_getMaxScrollExtent
(
contentSize
);
_hasVisualOverflow
=
_maxScrollExtent
>
0.0
;
...
...
@@ -506,13 +537,13 @@ class RenderEditable extends RenderBox {
@override
void
debugFillDescription
(
List
<
String
>
description
)
{
super
.
debugFillDescription
(
description
);
description
.
add
(
'cursorColor:
$
_
cursorColor
'
);
description
.
add
(
'showCursor:
$
_
showCursor
'
);
description
.
add
(
'maxLines:
$
_
maxLines
'
);
description
.
add
(
'selectionColor:
$
_
selectionColor
'
);
description
.
add
(
'cursorColor:
$cursorColor
'
);
description
.
add
(
'showCursor:
$showCursor
'
);
description
.
add
(
'maxLines:
$maxLines
'
);
description
.
add
(
'selectionColor:
$selectionColor
'
);
description
.
add
(
'textScaleFactor:
$textScaleFactor
'
);
description
.
add
(
'selection:
$
_
selection
'
);
description
.
add
(
'offset:
$
_
offset
'
);
description
.
add
(
'selection:
$selection
'
);
description
.
add
(
'offset:
$offset
'
);
}
@override
...
...
packages/flutter/lib/src/rendering/paragraph.dart
View file @
d74a5883
...
...
@@ -31,7 +31,11 @@ const String _kEllipsis = '\u2026';
class
RenderParagraph
extends
RenderBox
{
/// Creates a paragraph render object.
///
/// The [text], [overflow], and [softWrap] arguments must not be null.
/// The [text], [overflow], [softWrap], and [textScaleFactor] arguments must
/// not be null.
///
/// The [maxLines] property may be null (and indeed defaults to null), but if
/// it is not null, it must be greater than zero.
RenderParagraph
(
TextSpan
text
,
{
TextAlign
textAlign
,
bool
softWrap:
true
,
...
...
@@ -43,6 +47,7 @@ class RenderParagraph extends RenderBox {
assert
(
softWrap
!=
null
),
assert
(
overflow
!=
null
),
assert
(
textScaleFactor
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
_softWrap
=
softWrap
,
_overflow
=
overflow
,
_textPainter
=
new
TextPainter
(
...
...
@@ -77,7 +82,11 @@ class RenderParagraph extends RenderBox {
/// Whether the text should break at soft line breaks.
///
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
/// If false, the glyphs in the text will be positioned as if there was
/// unlimited horizontal space.
///
/// If [softWrap] is false, [overflow] and [textAlign] may have unexpected
/// effects.
bool
get
softWrap
=>
_softWrap
;
bool
_softWrap
;
set
softWrap
(
bool
value
)
{
...
...
@@ -116,9 +125,11 @@ class RenderParagraph extends RenderBox {
/// An optional maximum number of lines for the text to span, wrapping if necessary.
/// If the text exceeds the given number of lines, it will be truncated according
/// to [overflow].
/// to [overflow]
and [softWrap]
.
int
get
maxLines
=>
_textPainter
.
maxLines
;
/// The value may be null. If it is not null, then it must be greater than zero.
set
maxLines
(
int
value
)
{
assert
(
value
==
null
||
value
>
0
);
if
(
_textPainter
.
maxLines
==
value
)
return
;
_textPainter
.
maxLines
=
value
;
...
...
@@ -127,8 +138,7 @@ class RenderParagraph extends RenderBox {
}
void
_layoutText
({
double
minWidth:
0.0
,
double
maxWidth:
double
.
INFINITY
})
{
final
bool
wrap
=
_softWrap
||
(
_overflow
==
TextOverflow
.
ellipsis
&&
maxLines
==
null
);
_textPainter
.
layout
(
minWidth:
minWidth
,
maxWidth:
wrap
?
maxWidth
:
double
.
INFINITY
);
_textPainter
.
layout
(
minWidth:
minWidth
,
maxWidth:
_softWrap
?
maxWidth
:
double
.
INFINITY
);
}
void
_layoutTextWithConstraints
(
BoxConstraints
constraints
)
{
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
d74a5883
...
...
@@ -3028,7 +3028,11 @@ class Flow extends MultiChildRenderObjectWidget {
class
RichText
extends
LeafRenderObjectWidget
{
/// Creates a paragraph of rich text.
///
/// The [text], [softWrap], and [overflow] arguments must not be null.
/// The [text], [softWrap], [overflow], nad [textScaleFactor] arguments must
/// not be null.
///
/// The [maxLines] property may be null (and indeed defaults to null), but if
/// it is not null, it must be greater than zero.
const
RichText
({
Key
key
,
@required
this
.
text
,
...
...
@@ -3041,6 +3045,7 @@ class RichText extends LeafRenderObjectWidget {
assert
(
softWrap
!=
null
),
assert
(
overflow
!=
null
),
assert
(
textScaleFactor
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
super
(
key:
key
);
/// The text to display in this widget.
...
...
@@ -3066,6 +3071,9 @@ class RichText extends LeafRenderObjectWidget {
/// An optional maximum number of lines for the text to span, wrapping if necessary.
/// If the text exceeds the given number of lines, it will be truncated according
/// to [overflow].
///
/// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
/// edge of the box.
final
int
maxLines
;
@override
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
d74a5883
...
...
@@ -128,6 +128,10 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
class
EditableText
extends
StatefulWidget
{
/// Creates a basic text input control.
///
/// The [maxLines] property can be set to null to remove the restriction on
/// the number of lines. By default, it is 1, meaning this is a single-line
/// text field. If it is not null, it must be greater than zero.
///
/// The [controller], [focusNode], [style], and [cursorColor] arguments must
/// not be null.
EditableText
({
...
...
@@ -152,9 +156,9 @@ class EditableText extends StatefulWidget {
assert
(
obscureText
!=
null
),
assert
(
style
!=
null
),
assert
(
cursorColor
!=
null
),
assert
(
maxLines
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
assert
(
autofocus
!=
null
),
inputFormatters
=
maxLines
==
1
inputFormatters
=
maxLines
==
1
?
(
<
TextInputFormatter
>[
BlacklistingTextInputFormatter
.
singleLineFormatter
]
..
addAll
(
inputFormatters
??
const
Iterable
<
TextInputFormatter
>.
empty
())
...
...
@@ -192,8 +196,12 @@ class EditableText extends StatefulWidget {
final
Color
cursorColor
;
/// The maximum number of lines for the text to span, wrapping if necessary.
///
/// If this is 1 (the default), the text will not wrap, but will scroll
/// horizontally instead.
///
/// If this is null, there is no limit to the number of lines. If it is not
/// null, the value must be greater than zero.
final
int
maxLines
;
/// Whether this input field should focus itself if nothing else is already focused.
...
...
@@ -218,7 +226,7 @@ class EditableText extends StatefulWidget {
/// Called when the user indicates that they are done editing the text in the field.
final
ValueChanged
<
String
>
onSubmitted
;
/// Optional input validation and formatting overrides. Formatters are run
/// Optional input validation and formatting overrides. Formatters are run
/// in the provided order when the text input changes.
final
List
<
TextInputFormatter
>
inputFormatters
;
...
...
@@ -340,7 +348,7 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
}
bool
get
_hasFocus
=>
widget
.
focusNode
.
hasFocus
;
bool
get
_isMultiline
=>
widget
.
maxLines
>
1
;
bool
get
_isMultiline
=>
widget
.
maxLines
!=
1
;
// Calculate the new scroll offset so the cursor remains visible.
double
_getScrollOffsetForCaret
(
Rect
caretRect
)
{
...
...
@@ -417,7 +425,7 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
void
_handleSelectionChanged
(
TextSelection
selection
,
RenderEditable
renderObject
,
bool
longPress
)
{
widget
.
controller
.
selection
=
selection
;
//
Note that t
his will show the keyboard for all selection changes on the
//
T
his will show the keyboard for all selection changes on the
// EditableWidget, not just changes triggered by user gestures.
requestKeyboard
();
...
...
packages/flutter/lib/src/widgets/text.dart
View file @
d74a5883
...
...
@@ -14,6 +14,14 @@ class DefaultTextStyle extends InheritedWidget {
///
/// Consider using [DefaultTextStyle.merge] to inherit styling information
/// from the current default text style for a given [BuildContext].
///
/// The [style] and [child] arguments are required and must not be null.
///
/// The [softWrap] and [overflow] arguments must not be null (though they do
/// have default values).
///
/// The [maxLines] property may be null (and indeed defaults to null), but if
/// it is not null, it must be greater than zero.
const
DefaultTextStyle
({
Key
key
,
@required
this
.
style
,
...
...
@@ -25,6 +33,7 @@ class DefaultTextStyle extends InheritedWidget {
})
:
assert
(
style
!=
null
),
assert
(
softWrap
!=
null
),
assert
(
overflow
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
assert
(
child
!=
null
),
super
(
key:
key
,
child:
child
);
...
...
@@ -48,6 +57,15 @@ class DefaultTextStyle extends InheritedWidget {
/// for the [BuildContext] where the widget is inserted, and any of the other
/// arguments that are not null replace the corresponding properties on that
/// same default text style.
///
/// This constructor cannot be used to override the [maxLines] property of the
/// ancestor with the value null, since null here is used to mean "defer to
/// ancestor". To replace a non-null [maxLines] from an ancestor with the null
/// value (to remove the restriction on number of lines), manually obtain the
/// ambient [DefaultTextStyle] using [DefaultTextStyle.of], then create a new
/// [DefaultTextStyle] using the [new DefaultTextStyle] constructor directly.
/// See the source below for an example of how to do this (since that's
/// essentially what this constructor does).
static
Widget
merge
({
Key
key
,
TextStyle
style
,
...
...
@@ -91,6 +109,12 @@ class DefaultTextStyle extends InheritedWidget {
/// An optional maximum number of lines for the text to span, wrapping if necessary.
/// If the text exceeds the given number of lines, it will be truncated according
/// to [overflow].
///
/// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
/// edge of the box.
///
/// If this is non-null, it will override even explicit null values of
/// [Text.maxLines].
final
int
maxLines
;
/// The closest instance of this class that encloses the given context.
...
...
@@ -213,9 +237,17 @@ class Text extends StatelessWidget {
/// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope.
final
double
textScaleFactor
;
/// An optional maximum number of lines
the text is allowed to take up
.
/// An optional maximum number of lines
for the text to span, wrapping if necessary
.
/// If the text exceeds the given number of lines, it will be truncated according
/// to [overflow].
///
/// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
/// edge of the box.
///
/// If this is null, but there is an ambient [DefaultTextStyle] that specifies
/// an explicit number for its [DefaultTextStyle.maxLines], then the
/// [DefaultTextStyle] value will take precedence. You can use a [RichText]
/// widget directly to entirely override the [DefaultTextStyle].
final
int
maxLines
;
@override
...
...
@@ -232,7 +264,7 @@ class Text extends StatelessWidget {
maxLines:
maxLines
??
defaultTextStyle
.
maxLines
,
text:
new
TextSpan
(
style:
effectiveTextStyle
,
text:
data
text:
data
,
)
);
}
...
...
packages/flutter/test/material/text_field_test.dart
View file @
d74a5883
...
...
@@ -46,7 +46,7 @@ void main() {
'First line of text is '
'Second line goes until '
'Third line of stuff '
;
const
String
kFourLines
=
const
String
k
MoreThan
FourLines
=
kThreeLines
+
'Fourth line won
\'
t display and ends at'
;
...
...
@@ -462,7 +462,7 @@ void main() {
);
}
await
tester
.
pumpWidget
(
builder
(
3
));
await
tester
.
pumpWidget
(
builder
(
null
));
RenderBox
findInputBox
()
=>
tester
.
renderObject
(
find
.
byKey
(
textFieldKey
));
...
...
@@ -470,28 +470,44 @@ void main() {
final
Size
emptyInputSize
=
inputBox
.
size
;
await
tester
.
enterText
(
find
.
byType
(
TextField
),
'No wrapping here.'
);
await
tester
.
pumpWidget
(
builder
(
3
));
await
tester
.
pumpWidget
(
builder
(
null
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
equals
(
emptyInputSize
));
await
tester
.
enterText
(
find
.
byType
(
TextField
),
kThreeLines
);
await
tester
.
pumpWidget
(
builder
(
3
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
greaterThan
(
emptyInputSize
));
final
Size
threeLineInputSize
=
inputBox
.
size
;
await
tester
.
enterText
(
find
.
byType
(
TextField
),
kThreeLines
);
await
tester
.
pumpWidget
(
builder
(
null
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
greaterThan
(
emptyInputSize
));
await
tester
.
enterText
(
find
.
byType
(
TextField
),
kThreeLines
);
await
tester
.
pumpWidget
(
builder
(
null
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
threeLineInputSize
);
// An extra line won't increase the size because we max at 3.
await
tester
.
enterText
(
find
.
byType
(
TextField
),
kFourLines
);
await
tester
.
enterText
(
find
.
byType
(
TextField
),
k
MoreThan
FourLines
);
await
tester
.
pumpWidget
(
builder
(
3
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
threeLineInputSize
);
// But now it will.
await
tester
.
enterText
(
find
.
byType
(
TextField
),
kFourLines
);
// But now it will.
.. but it will max at four
await
tester
.
enterText
(
find
.
byType
(
TextField
),
k
MoreThan
FourLines
);
await
tester
.
pumpWidget
(
builder
(
4
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
greaterThan
(
threeLineInputSize
));
final
Size
fourLineInputSize
=
inputBox
.
size
;
// Now it won't max out until the end
await
tester
.
pumpWidget
(
builder
(
null
));
expect
(
findInputBox
(),
equals
(
inputBox
));
expect
(
inputBox
.
size
,
greaterThan
(
fourLineInputSize
));
});
testWidgets
(
'Can drag handles to change selection in multiline'
,
(
WidgetTester
tester
)
async
{
...
...
@@ -594,7 +610,7 @@ void main() {
await
tester
.
pumpWidget
(
builder
());
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
tester
.
enterText
(
find
.
byType
(
TextField
),
kFourLines
);
await
tester
.
enterText
(
find
.
byType
(
TextField
),
k
MoreThan
FourLines
);
await
tester
.
pumpWidget
(
builder
());
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
...
...
@@ -603,8 +619,8 @@ void main() {
final
RenderBox
inputBox
=
findInputBox
();
// Check that the last line of text is not displayed.
final
Offset
firstPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'First'
));
final
Offset
fourthPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'Fourth'
));
final
Offset
firstPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'First'
));
final
Offset
fourthPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'Fourth'
));
expect
(
firstPos
.
dx
,
fourthPos
.
dx
);
expect
(
firstPos
.
dy
,
lessThan
(
fourthPos
.
dy
));
expect
(
inputBox
.
hitTest
(
new
HitTestResult
(),
position:
inputBox
.
globalToLocal
(
firstPos
)),
isTrue
);
...
...
@@ -622,8 +638,8 @@ void main() {
await
tester
.
pump
();
// Now the first line is scrolled up, and the fourth line is visible.
Offset
newFirstPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'First'
));
Offset
newFourthPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'Fourth'
));
Offset
newFirstPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'First'
));
Offset
newFourthPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'Fourth'
));
expect
(
newFirstPos
.
dy
,
lessThan
(
firstPos
.
dy
));
expect
(
inputBox
.
hitTest
(
new
HitTestResult
(),
position:
inputBox
.
globalToLocal
(
newFirstPos
)),
isFalse
);
...
...
@@ -633,7 +649,7 @@ void main() {
// Long press the 'i' in 'Fourth line' to select the word.
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
final
Offset
untilPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'Fourth line'
)+
8
);
final
Offset
untilPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'Fourth line'
)+
8
);
gesture
=
await
tester
.
startGesture
(
untilPos
,
pointer:
7
);
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
gesture
.
up
();
...
...
@@ -645,7 +661,7 @@ void main() {
// Drag the left handle to the first line, just after 'First'.
final
Offset
handlePos
=
endpoints
[
0
].
point
+
const
Offset
(-
1.0
,
1.0
);
final
Offset
newHandlePos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'First'
)
+
5
);
final
Offset
newHandlePos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'First'
)
+
5
);
gesture
=
await
tester
.
startGesture
(
handlePos
,
pointer:
7
);
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
await
gesture
.
moveTo
(
newHandlePos
+
const
Offset
(
0.0
,
-
10.0
));
...
...
@@ -655,8 +671,8 @@ void main() {
// The text should have scrolled up with the handle to keep the active
// cursor visible, back to its original position.
newFirstPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'First'
));
newFourthPos
=
textOffsetToPosition
(
tester
,
kFourLines
.
indexOf
(
'Fourth'
));
newFirstPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'First'
));
newFourthPos
=
textOffsetToPosition
(
tester
,
k
MoreThan
FourLines
.
indexOf
(
'Fourth'
));
expect
(
newFirstPos
.
dy
,
firstPos
.
dy
);
expect
(
inputBox
.
hitTest
(
new
HitTestResult
(),
position:
inputBox
.
globalToLocal
(
newFirstPos
)),
isTrue
);
expect
(
inputBox
.
hitTest
(
new
HitTestResult
(),
position:
inputBox
.
globalToLocal
(
newFourthPos
)),
isFalse
);
...
...
packages/flutter/test/rendering/paragraph_test.dart
View file @
d74a5883
...
...
@@ -79,12 +79,13 @@ void main() {
const
TextSpan
(
text:
'This
\n
'
// 4 characters * 10px font size = 40px width on the first line
'is a wrapping test. It should wrap at manual newlines, and if softWrap is true, also at spaces.'
,
style:
const
TextStyle
(
fontFamily:
'Ahem'
,
fontSize:
10.0
)),
style:
const
TextStyle
(
fontFamily:
'Ahem'
,
fontSize:
10.0
),
),
maxLines:
1
,
softWrap:
true
,
);
void
relayoutWith
({
int
maxLines
,
bool
softWrap
,
TextOverflow
overflow
})
{
void
relayoutWith
({
int
maxLines
,
bool
softWrap
,
TextOverflow
overflow
})
{
paragraph
..
maxLines
=
maxLines
..
softWrap
=
softWrap
...
...
@@ -147,5 +148,34 @@ void main() {
relayoutWith
(
maxLines:
100
,
softWrap:
true
,
overflow:
TextOverflow
.
fade
);
expect
(
paragraph
.
debugHasOverflowShader
,
isFalse
);
});
test
(
'maxLines'
,
()
{
final
RenderParagraph
paragraph
=
new
RenderParagraph
(
const
TextSpan
(
text:
'How do you write like you
\'
re running out of time? Write day and night like you
\'
re running out of time?'
,
// 0123456789 0123456789 012 345 0123456 012345 01234 012345678 012345678 0123 012 345 0123456 012345 01234
// 0 1 2 3 4 5 6 7 8 9 10 11 12
style:
const
TextStyle
(
fontFamily:
'Ahem'
,
fontSize:
10.0
),
),
);
layout
(
paragraph
,
constraints:
const
BoxConstraints
(
maxWidth:
100.0
));
void
layoutAt
(
int
maxLines
)
{
paragraph
.
maxLines
=
maxLines
;
pumpFrame
();
}
layoutAt
(
null
);
expect
(
paragraph
.
size
.
height
,
130.0
);
layoutAt
(
1
);
expect
(
paragraph
.
size
.
height
,
10.0
);
layoutAt
(
2
);
expect
(
paragraph
.
size
.
height
,
20.0
);
layoutAt
(
3
);
expect
(
paragraph
.
size
.
height
,
30.0
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment