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
a7360d24
Commit
a7360d24
authored
Nov 16, 2016
by
Hans Muller
Committed by
GitHub
Nov 16, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Factor out Input's layout: add InputContainer etc (#6881)
parent
7c56f00f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
215 additions
and
109 deletions
+215
-109
input.dart
packages/flutter/lib/src/material/input.dart
+215
-109
No files found.
packages/flutter/lib/src/material/input.dart
View file @
a7360d24
...
...
@@ -10,12 +10,31 @@ import 'debug.dart';
import
'icon.dart'
;
import
'icon_theme.dart'
;
import
'icon_theme_data.dart'
;
import
'material.dart'
;
import
'text_selection.dart'
;
import
'theme.dart'
;
export
'package:flutter/services.dart'
show
TextInputType
;
const
Duration
_kTransitionDuration
=
const
Duration
(
milliseconds:
200
);
const
Curve
_kTransitionCurve
=
Curves
.
fastOutSlowIn
;
/// A simple text input field.
///
/// This widget is comparable to [Text] in that it does not include a margin
/// or any decoration outside the text itself. It is useful for applications,
/// like a search box, that don't need any additional decoration. It should
/// also be useful in custom widgets that support text input.
///
/// The [value] field must be updated each time the [onChanged] callback is
/// invoked. Be sure to include the full [value] provided by the [onChanged]
/// callback, or information like the current selection will be lost.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// See also:
///
/// * [Input], which adds a label, a divider below the text field, and support for
/// an error message.
class
InputField
extends
StatefulWidget
{
InputField
({
Key
key
,
...
...
@@ -119,7 +138,8 @@ class _InputFieldState extends State<InputField> {
];
if
(
config
.
hintText
!=
null
&&
value
.
text
.
isEmpty
)
{
TextStyle
hintStyle
=
themeData
.
textTheme
.
subhead
.
copyWith
(
color:
themeData
.
hintColor
);
TextStyle
hintStyle
=
textStyle
.
copyWith
(
color:
themeData
.
hintColor
);
stackChildren
.
add
(
new
Positioned
(
left:
0.0
,
...
...
@@ -135,52 +155,31 @@ class _InputFieldState extends State<InputField> {
}
}
/// A material design text input field.
/// Displays the visual elements of a material design text field around an
/// arbitrary child widget.
///
/// Requires one of its ancestors to be a [Material] widget.
/// Use InputContainer to create widgets that look and behave like the [Input]
/// widget.
///
/// The [value] field must be updated each time the [onChanged] callback is
/// invoked. Be sure to include the full [value] provided by the [onChanged]
/// callback, or information like the current selection will be lost.
/// Requires one of its ancestors to be a [Material] widget.
///
/// See also:
///
/// * <https://material.google.com/components/text-fields.html>
///
/// For a detailed guide on using the input widget, see:
///
/// * <https://flutter.io/text-input/>
class
Input
extends
StatefulWidget
{
/// Creates a text input field.
///
/// By default, the input uses a keyboard appropriate for text entry.
//
// Note: If you change this constructor signature, please also update
// InputFormField below.
Input
({
/// * [Input], which combines an [InputContainer] with an [InputField].
class
InputContainer
extends
StatefulWidget
{
InputContainer
({
Key
key
,
this
.
valu
e
,
this
.
keyboardType
:
TextInputType
.
text
,
this
.
focused
:
fals
e
,
this
.
isEmpty
:
false
,
this
.
icon
,
this
.
labelText
,
this
.
hintText
,
this
.
errorText
,
this
.
style
,
this
.
hideText
:
false
,
this
.
isDense
:
false
,
this
.
autofocus
:
false
,
this
.
maxLines
:
1
,
this
.
onChanged
,
this
.
onSubmitted
,
this
.
child
,
})
:
super
(
key:
key
);
/// The current state of text of the input field. This includes the selected
/// text, if any, among other things.
final
InputValue
value
;
/// The type of keyboard to use for editing the text.
final
TextInputType
keyboardType
;
/// An icon to show adjacent to the input field.
///
/// The size and color of the icon is configured automatically using an
...
...
@@ -190,68 +189,46 @@ class Input extends StatefulWidget {
/// See [Icon], [ImageIcon].
final
Widget
icon
;
/// Text t
o show above the input field
.
/// Text t
hat appears above the child or over it, if isEmpty is true
.
final
String
labelText
;
/// Text t
o show inline in the input field when it would otherwise be empty
.
/// Text t
hat appears over the child if isEmpty is true and labelText is null
.
final
String
hintText
;
/// Text to show when the input text is invalid.
/// Text that appears below the child. If errorText is non-null the divider
/// that appears below the child is red.
final
String
errorText
;
/// The style to use for the text being edited.
/// The style to use for the hint. It's also used for the label when the label
/// appears over the child.
final
TextStyle
style
;
/// Whether to hide the text being edited (e.g., for passwords).
///
/// When this is set to true, all the characters in the input are replaced by
/// U+2022 BULLET characters (•).
final
bool
hideText
;
/// Whether the input field is part of a dense form (i.e., uses less vertical space).
/// Whether the input container is part of a dense form (i.e., uses less vertical space).
final
bool
isDense
;
///
Whether this input field should focus itself if nothing else is already focused
.
final
bool
autofocus
;
///
True if the hint and label should be displayed as if the child had the focus
.
final
bool
focused
;
/// 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.
final
int
maxLines
;
/// Should the hint and label be displayed as if no value had been input
/// to the child.
final
bool
isEmpty
;
/// Called when the text being edited changes.
///
/// The [value] must be updated each time [onChanged] is invoked.
final
ValueChanged
<
InputValue
>
onChanged
;
/// Called when the user indicates that they are done editing the text in the field.
final
ValueChanged
<
InputValue
>
onSubmitted
;
final
Widget
child
;
@override
_Input
State
createState
()
=>
new
_Input
State
();
_Input
ContainerState
createState
()
=>
new
_InputContainer
State
();
}
const
Duration
_kTransitionDuration
=
const
Duration
(
milliseconds:
200
);
const
Curve
_kTransitionCurve
=
Curves
.
fastOutSlowIn
;
class
_InputState
extends
State
<
Input
>
{
GlobalKey
<
_InputFieldState
>
_inputFieldKey
=
new
GlobalKey
<
_InputFieldState
>(
debugLabel:
'_InputState _inputFieldKey'
);
GlobalKey
<
_InputFieldState
>
_focusKey
=
new
GlobalKey
(
debugLabel:
'_InputState _focusKey'
);
GlobalKey
get
focusKey
=>
config
.
key
is
GlobalKey
?
config
.
key
:
_focusKey
;
class
_InputContainerState
extends
State
<
InputContainer
>
{
@override
Widget
build
(
BuildContext
context
)
{
assert
(
debugCheckHasMaterial
(
context
));
ThemeData
themeData
=
Theme
.
of
(
context
);
BuildContext
focusContext
=
focusKey
.
currentContext
;
bool
focused
=
focusContext
!=
null
&&
Focus
.
at
(
focusContext
,
autofocus:
config
.
autofocus
);
InputValue
value
=
config
.
value
??
InputValue
.
empty
;
String
errorText
=
config
.
errorText
;
TextStyle
textStyle
=
config
.
style
??
themeData
.
textTheme
.
subhead
;
final
TextStyle
textStyle
=
config
.
style
??
themeData
.
textTheme
.
subhead
;
Color
activeColor
=
themeData
.
hintColor
;
if
(
focused
)
{
if
(
config
.
focused
)
{
switch
(
themeData
.
brightness
)
{
case
Brightness
.
dark
:
activeColor
=
themeData
.
accentColor
;
...
...
@@ -265,10 +242,14 @@ class _InputState extends State<Input> {
List
<
Widget
>
stackChildren
=
<
Widget
>[];
final
bool
hasInlineLabel
=
config
.
labelText
!=
null
&&
!
focused
&&
!
value
.
text
.
isNotEmpty
;
// If we're not focused, there's not value, and labelText was provided,
// then the label appears where the hint would. And we will not show
// the hintText.
final
bool
hasInlineLabel
=
!
config
.
focused
&&
config
.
labelText
!=
null
&&
config
.
isEmpty
;
if
(
config
.
labelText
!=
null
)
{
final
TextStyle
labelStyle
=
hasInlineLabel
?
t
hemeData
.
textTheme
.
subhead
.
copyWith
(
color:
themeData
.
hintColor
)
:
t
extStyle
.
copyWith
(
color:
themeData
.
hintColor
)
:
themeData
.
textTheme
.
caption
.
copyWith
(
color:
activeColor
);
final
double
topPaddingIncrement
=
themeData
.
textTheme
.
caption
.
fontSize
+
(
config
.
isDense
?
4.0
:
8.0
);
...
...
@@ -282,21 +263,29 @@ class _InputState extends State<Input> {
top:
top
,
duration:
_kTransitionDuration
,
curve:
_kTransitionCurve
,
child:
new
AnimatedOpacity
(
opacity:
focused
?
1.0
:
0.0
,
curve:
_kTransitionCurve
,
duration:
_kTransitionDuration
,
child:
new
Text
(
config
.
labelText
,
style:
labelStyle
)
),
child:
new
Text
(
config
.
labelText
,
style:
labelStyle
),
),
);
topPadding
+=
topPaddingIncrement
;
}
if
(
config
.
hintText
!=
null
&&
config
.
isEmpty
&&
!
hasInlineLabel
)
{
TextStyle
hintStyle
=
textStyle
.
copyWith
(
color:
themeData
.
hintColor
);
stackChildren
.
add
(
new
Positioned
(
left:
0.0
,
top:
topPadding
+
textStyle
.
fontSize
-
hintStyle
.
fontSize
,
child:
new
IgnorePointer
(
child:
new
Text
(
config
.
hintText
,
style:
hintStyle
),
),
),
);
}
Color
borderColor
=
activeColor
;
double
bottomPadding
=
8.0
;
double
bottomBorder
=
focused
?
2.0
:
1.0
;
double
bottomBorder
=
config
.
focused
?
2.0
:
1.0
;
double
bottomHeight
=
config
.
isDense
?
14.0
:
18.0
;
if
(
errorText
!=
null
)
{
...
...
@@ -323,26 +312,7 @@ class _InputState extends State<Input> {
decoration:
new
BoxDecoration
(
border:
border
,
),
// Since the focusKey may have been created here, defer building the
// InputField until the focusKey's context has been set. This is necessary
// because our descendants may check the focus, like Focus.at(focusContext),
// when they build.
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
return
new
InputField
(
key:
_inputFieldKey
,
focusKey:
focusKey
,
value:
value
,
style:
textStyle
,
hideText:
config
.
hideText
,
maxLines:
config
.
maxLines
,
keyboardType:
config
.
keyboardType
,
hintText:
config
.
hintText
,
onChanged:
config
.
onChanged
,
onSubmitted:
config
.
onSubmitted
,
);
}
),
child:
config
.
child
,
));
if
(
errorText
!=
null
&&
!
config
.
isDense
)
{
...
...
@@ -354,12 +324,12 @@ class _InputState extends State<Input> {
));
}
Widget
chi
ld
=
new
Stack
(
children:
stackChildren
);
Widget
textFie
ld
=
new
Stack
(
children:
stackChildren
);
if
(
config
.
icon
!=
null
)
{
double
iconSize
=
config
.
isDense
?
18.0
:
24.0
;
double
iconTop
=
topPadding
+
(
textStyle
.
fontSize
-
iconSize
)
/
2.0
;
chi
ld
=
new
Row
(
textFie
ld
=
new
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
<
Widget
>[
new
Container
(
...
...
@@ -368,24 +338,160 @@ class _InputState extends State<Input> {
child:
new
IconTheme
.
merge
(
context:
context
,
data:
new
IconThemeData
(
color:
focused
?
activeColor
:
Colors
.
black45
,
color:
config
.
focused
?
activeColor
:
Colors
.
black45
,
size:
config
.
isDense
?
18.0
:
24.0
),
child:
config
.
icon
)
),
new
Flexible
(
child:
chi
ld
)
new
Flexible
(
child:
textFie
ld
)
]
);
}
return
textField
;
}
}
/// A material design text input field.
///
/// The [value] field must be updated each time the [onChanged] callback is
/// invoked. Be sure to include the full [value] provided by the [onChanged]
/// callback, or information like the current selection will be lost.
///
/// Requires one of its ancestors to be a [Material] widget.
///
/// See also:
///
/// * <https://material.google.com/components/text-fields.html>
///
/// For a detailed guide on using the input widget, see:
///
/// * <https://flutter.io/text-input/>
class
Input
extends
StatefulWidget
{
/// Creates a text input field.
///
/// By default, the input uses a keyboard appropriate for text entry.
//
// If you change this constructor signature, please also update
// InputContainer, InputFormField, InputField.
Input
({
Key
key
,
this
.
value
,
this
.
keyboardType
:
TextInputType
.
text
,
this
.
icon
,
this
.
labelText
,
this
.
hintText
,
this
.
errorText
,
this
.
style
,
this
.
hideText
:
false
,
this
.
isDense
:
false
,
this
.
autofocus
:
false
,
this
.
maxLines
:
1
,
this
.
onChanged
,
this
.
onSubmitted
,
})
:
super
(
key:
key
);
/// The current state of text of the input field. This includes the selected
/// text, if any, among other things.
final
InputValue
value
;
/// The type of keyboard to use for editing the text.
final
TextInputType
keyboardType
;
/// An icon to show adjacent to the input field.
///
/// The size and color of the icon is configured automatically using an
/// [IconTheme] and therefore does not need to be explicitly given in the
/// icon widget.
///
/// See [Icon], [ImageIcon].
final
Widget
icon
;
/// Text to show above the input field.
final
String
labelText
;
/// Text to show inline in the input field when it would otherwise be empty.
final
String
hintText
;
/// Text to show when the input text is invalid.
final
String
errorText
;
/// The style to use for the text being edited.
final
TextStyle
style
;
/// Whether to hide the text being edited (e.g., for passwords).
///
/// When this is set to true, all the characters in the input are replaced by
/// U+2022 BULLET characters (•).
final
bool
hideText
;
/// Whether the input field is part of a dense form (i.e., uses less vertical space).
final
bool
isDense
;
/// Whether this input field should focus itself if nothing else is already focused.
final
bool
autofocus
;
/// 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.
final
int
maxLines
;
/// Called when the text being edited changes.
///
/// The [value] must be updated each time [onChanged] is invoked.
final
ValueChanged
<
InputValue
>
onChanged
;
/// Called when the user indicates that they are done editing the text in the field.
final
ValueChanged
<
InputValue
>
onSubmitted
;
@override
_InputState
createState
()
=>
new
_InputState
();
}
class
_InputState
extends
State
<
Input
>
{
final
GlobalKey
<
_InputFieldState
>
_inputFieldKey
=
new
GlobalKey
<
_InputFieldState
>();
final
GlobalKey
_focusKey
=
new
GlobalKey
();
GlobalKey
get
focusKey
=>
config
.
key
is
GlobalKey
?
config
.
key
:
_focusKey
;
@override
Widget
build
(
BuildContext
context
)
{
return
new
GestureDetector
(
key:
config
.
key
is
GlobalKey
?
null
:
focusKey
,
behavior:
HitTestBehavior
.
opaque
,
key:
focusKey
==
_focusKey
?
_focusKey
:
null
,
onTap:
()
{
_inputFieldKey
.
currentState
?.
requestKeyboard
();
},
child:
child
,
// Since the focusKey may have been created here, defer building the
// InputContainer until the focusKey's context has been set. This is
// necessary because we're passing the value of Focus.at() along.
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
final
bool
focused
=
Focus
.
at
(
focusKey
.
currentContext
,
autofocus:
config
.
autofocus
);
final
bool
isEmpty
=
(
config
.
value
??
InputValue
.
empty
).
text
.
isEmpty
;
return
new
InputContainer
(
focused:
focused
,
isEmpty:
isEmpty
,
icon:
config
.
icon
,
labelText:
config
.
labelText
,
hintText:
config
.
hintText
,
errorText:
config
.
errorText
,
style:
config
.
style
,
isDense:
config
.
isDense
,
child:
new
InputField
(
key:
_inputFieldKey
,
focusKey:
focusKey
,
value:
config
.
value
,
style:
config
.
style
,
hideText:
config
.
hideText
,
maxLines:
config
.
maxLines
,
keyboardType:
config
.
keyboardType
,
onChanged:
config
.
onChanged
,
onSubmitted:
config
.
onSubmitted
,
),
);
},
),
);
}
}
...
...
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