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
27eeb972
Unverified
Commit
27eeb972
authored
Jan 13, 2018
by
Hans Muller
Committed by
GitHub
Jan 13, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TextField splash integration (#14055)
parent
c09736bb
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
370 additions
and
31 deletions
+370
-31
ink_ripple.dart
packages/flutter/lib/src/material/ink_ripple.dart
+10
-17
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+108
-6
editable.dart
packages/flutter/lib/src/rendering/editable.dart
+31
-4
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+25
-3
ink_paint_test.dart
packages/flutter/test/material/ink_paint_test.dart
+2
-1
text_field_splash_test.dart
packages/flutter/test/material/text_field_splash_test.dart
+194
-0
No files found.
packages/flutter/lib/src/material/ink_ripple.dart
View file @
27eeb972
...
...
@@ -14,11 +14,11 @@ import 'material.dart';
const
Duration
_kUnconfirmedRippleDuration
=
const
Duration
(
seconds:
1
);
const
Duration
_kFadeInDuration
=
const
Duration
(
milliseconds:
75
);
const
Duration
_kRadiusDuration
=
const
Duration
(
milliseconds:
225
);
const
Duration
_kFadeOutDuration
=
const
Duration
(
milliseconds:
450
);
const
Duration
_kFadeOutDuration
=
const
Duration
(
milliseconds:
375
);
const
Duration
_kCancelDuration
=
const
Duration
(
milliseconds:
75
);
// The fade out begins
300
ms after the _fadeOutController starts. See confirm().
const
double
_kFadeOutIntervalStart
=
300.0
/
450
.0
;
// The fade out begins
225
ms after the _fadeOutController starts. See confirm().
const
double
_kFadeOutIntervalStart
=
225.0
/
375
.0
;
RectCallback
_getClipCallback
(
RenderBox
referenceBox
,
bool
containedInkWell
,
RectCallback
rectCallback
)
{
if
(
rectCallback
!=
null
)
{
...
...
@@ -31,19 +31,10 @@ RectCallback _getClipCallback(RenderBox referenceBox, bool containedInkWell, Rec
}
double
_getTargetRadius
(
RenderBox
referenceBox
,
bool
containedInkWell
,
RectCallback
rectCallback
,
Offset
position
)
{
if
(
containedInkWell
)
{
final
Size
size
=
rectCallback
!=
null
?
rectCallback
().
size
:
referenceBox
.
size
;
return
_getRippleRadiusForPositionInSize
(
size
,
position
);
}
return
Material
.
defaultSplashRadius
;
}
double
_getRippleRadiusForPositionInSize
(
Size
bounds
,
Offset
position
)
{
final
double
d1
=
(
position
-
bounds
.
topLeft
(
Offset
.
zero
)).
distance
;
final
double
d2
=
(
position
-
bounds
.
topRight
(
Offset
.
zero
)).
distance
;
final
double
d3
=
(
position
-
bounds
.
bottomLeft
(
Offset
.
zero
)).
distance
;
final
double
d4
=
(
position
-
bounds
.
bottomRight
(
Offset
.
zero
)).
distance
;
return
math
.
max
(
math
.
max
(
d1
,
d2
),
math
.
max
(
d3
,
d4
)).
ceilToDouble
();
final
Size
size
=
rectCallback
!=
null
?
rectCallback
().
size
:
referenceBox
.
size
;
final
double
d1
=
size
.
bottomRight
(
Offset
.
zero
).
distance
;
final
double
d2
=
(
size
.
topRight
(
Offset
.
zero
)
-
size
.
bottomLeft
(
Offset
.
zero
)).
distance
;
return
math
.
max
(
d1
,
d2
)
/
2.0
;
}
class
_InkRippleFactory
extends
InteractiveInkFeatureFactory
{
...
...
@@ -205,7 +196,9 @@ class InkRipple extends InteractiveInkFeature {
@override
void
cancel
()
{
_fadeInController
.
stop
();
_fadeOutController
.
animateTo
(
1.0
,
duration:
_kCancelDuration
);
_fadeOutController
..
value
=
1.0
-
_fadeInController
.
value
..
animateTo
(
1.0
,
duration:
_kCancelDuration
);
}
void
_handleAlphaStatusChanged
(
AnimationStatus
status
)
{
...
...
packages/flutter/lib/src/material/text_field.dart
View file @
27eeb972
...
...
@@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:collection'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
import
'feedback.dart'
;
import
'ink_well.dart'
show
InteractiveInkFeature
;
import
'input_decorator.dart'
;
import
'material.dart'
;
import
'text_selection.dart'
;
...
...
@@ -275,9 +279,12 @@ class TextField extends StatefulWidget {
}
}
class
_TextFieldState
extends
State
<
TextField
>
{
class
_TextFieldState
extends
State
<
TextField
>
with
AutomaticKeepAliveClientMixin
{
final
GlobalKey
<
EditableTextState
>
_editableTextKey
=
new
GlobalKey
<
EditableTextState
>();
Set
<
InteractiveInkFeature
>
_splashes
;
InteractiveInkFeature
_currentSplash
;
TextEditingController
_controller
;
TextEditingController
get
_effectiveController
=>
widget
.
controller
??
_controller
;
...
...
@@ -332,13 +339,104 @@ class _TextFieldState extends State<TextField> {
_editableTextKey
.
currentState
?.
requestKeyboard
();
}
void
_
onSelectionChanged
(
BuildContext
context
,
SelectionChangedCause
cause
)
{
void
_
handleSelectionChanged
(
TextSelection
selection
,
SelectionChangedCause
cause
)
{
if
(
cause
==
SelectionChangedCause
.
longPress
)
Feedback
.
forLongPress
(
context
);
}
InteractiveInkFeature
_createInkFeature
(
TapDownDetails
details
)
{
final
MaterialInkController
inkController
=
Material
.
of
(
context
);
final
RenderBox
referenceBox
=
InputDecorator
.
containerOf
(
_editableTextKey
.
currentContext
);
final
Offset
position
=
referenceBox
.
globalToLocal
(
details
.
globalPosition
);
final
Color
color
=
Theme
.
of
(
context
).
splashColor
;
InteractiveInkFeature
splash
;
void
handleRemoved
()
{
if
(
_splashes
!=
null
)
{
assert
(
_splashes
.
contains
(
splash
));
_splashes
.
remove
(
splash
);
if
(
_currentSplash
==
splash
)
_currentSplash
=
null
;
updateKeepAlive
();
}
// else we're probably in deactivate()
}
splash
=
Theme
.
of
(
context
).
splashFactory
.
create
(
controller:
inkController
,
referenceBox:
referenceBox
,
position:
position
,
color:
color
,
containedInkWell:
true
,
// TODO(hansmuller): splash clip borderRadius should match the input decorator's border.
borderRadius:
BorderRadius
.
zero
,
onRemoved:
handleRemoved
,
);
return
splash
;
}
RenderEditable
get
_renderEditable
=>
_editableTextKey
.
currentState
.
renderEditable
;
void
_handleTapDown
(
TapDownDetails
details
)
{
_renderEditable
.
handleTapDown
(
details
);
_startSplash
(
details
);
}
void
_handleTap
()
{
_renderEditable
.
handleTap
();
_requestKeyboard
();
_confirmCurrentSplash
();
}
void
_handleTapCancel
()
{
_renderEditable
.
handleTapCancel
();
_cancelCurrentSplash
();
}
void
_handleLongPress
()
{
_renderEditable
.
handleLongPress
();
_confirmCurrentSplash
();
}
void
_startSplash
(
TapDownDetails
details
)
{
if
(
_effectiveFocusNode
.
hasFocus
)
return
;
final
InteractiveInkFeature
splash
=
_createInkFeature
(
details
);
_splashes
??=
new
HashSet
<
InteractiveInkFeature
>();
_splashes
.
add
(
splash
);
_currentSplash
=
splash
;
updateKeepAlive
();
}
void
_confirmCurrentSplash
()
{
_currentSplash
?.
confirm
();
_currentSplash
=
null
;
}
void
_cancelCurrentSplash
()
{
_currentSplash
?.
cancel
();
_currentSplash
=
null
;
}
@override
bool
get
wantKeepAlive
=>
_splashes
!=
null
&&
_splashes
.
isNotEmpty
;
@override
void
deactivate
()
{
if
(
_splashes
!=
null
)
{
final
Set
<
InteractiveInkFeature
>
splashes
=
_splashes
;
_splashes
=
null
;
for
(
InteractiveInkFeature
splash
in
splashes
)
splash
.
dispose
();
_currentSplash
=
null
;
}
assert
(
_currentSplash
==
null
);
super
.
deactivate
();
}
@override
Widget
build
(
BuildContext
context
)
{
super
.
build
(
context
);
// See AutomaticKeepAliveClientMixin.
final
ThemeData
themeData
=
Theme
.
of
(
context
);
final
TextStyle
style
=
widget
.
style
??
themeData
.
textTheme
.
subhead
;
final
TextEditingController
controller
=
_effectiveController
;
...
...
@@ -366,8 +464,9 @@ class _TextFieldState extends State<TextField> {
:
materialTextSelectionControls
,
onChanged:
widget
.
onChanged
,
onSubmitted:
widget
.
onSubmitted
,
onSelectionChanged:
(
TextSelection
_
,
SelectionChangedCause
cause
)
=>
_onSelectionChanged
(
context
,
cause
)
,
onSelectionChanged:
_handleSelectionChanged
,
inputFormatters:
formatters
,
rendererIgnoresPointer:
true
,
),
);
...
...
@@ -395,10 +494,13 @@ class _TextFieldState extends State<TextField> {
_requestKeyboard
();
},
child:
new
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
onTap:
_requestKeyboard
,
child:
child
,
behavior:
HitTestBehavior
.
translucent
,
onTapDown:
_handleTapDown
,
onTap:
_handleTap
,
onTapCancel:
_handleTapCancel
,
onLongPress:
_handleLongPress
,
excludeFromSemantics:
true
,
child:
child
,
),
);
}
...
...
packages/flutter/lib/src/rendering/editable.dart
View file @
27eeb972
...
...
@@ -131,11 +131,13 @@ class RenderEditable extends RenderBox {
@required
ViewportOffset
offset
,
this
.
onSelectionChanged
,
this
.
onCaretChanged
,
this
.
ignorePointer
:
false
,
})
:
assert
(
textAlign
!=
null
),
assert
(
textDirection
!=
null
,
'RenderEditable created without a textDirection.'
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
assert
(
textScaleFactor
!=
null
),
assert
(
offset
!=
null
),
assert
(
ignorePointer
!=
null
),
_textPainter
=
new
TextPainter
(
text:
text
,
textAlign:
textAlign
,
...
...
@@ -167,6 +169,13 @@ class RenderEditable extends RenderBox {
/// Called during the paint phase when the caret location changes.
CaretChangedHandler
onCaretChanged
;
/// If true [handleEvent] does nothing and it's assumed that this
/// renderer will be notified of input gestures via [handleTapDown],
/// [handleTap], [handleTapCancel], and [handleLongPress].
///
/// The default value of this property is false.
bool
ignorePointer
;
Rect
_lastCaretRect
;
/// Marks the render object as needing to be laid out again and have its text
...
...
@@ -550,6 +559,8 @@ class RenderEditable extends RenderBox {
@override
void
handleEvent
(
PointerEvent
event
,
BoxHitTestEntry
entry
)
{
if
(
ignorePointer
)
return
;
assert
(
debugHandleEvent
(
event
,
entry
));
if
(
event
is
PointerDownEvent
&&
onSelectionChanged
!=
null
)
{
_tap
.
addPointer
(
event
);
...
...
@@ -559,11 +570,15 @@ class RenderEditable extends RenderBox {
Offset
_lastTapDownPosition
;
Offset
_longPressPosition
;
void
_
handleTapDown
(
TapDownDetails
details
)
{
void
handleTapDown
(
TapDownDetails
details
)
{
_lastTapDownPosition
=
details
.
globalPosition
+
-
_paintOffset
;
}
void
_handleTapDown
(
TapDownDetails
details
)
{
assert
(!
ignorePointer
);
handleTapDown
(
details
);
}
void
_
handleTap
()
{
void
handleTap
()
{
_layoutText
(
constraints
.
maxWidth
);
assert
(
_lastTapDownPosition
!=
null
);
final
Offset
globalPosition
=
_lastTapDownPosition
;
...
...
@@ -573,14 +588,22 @@ class RenderEditable extends RenderBox {
onSelectionChanged
(
new
TextSelection
.
fromPosition
(
position
),
this
,
SelectionChangedCause
.
tap
);
}
}
void
_handleTap
()
{
assert
(!
ignorePointer
);
handleTap
();
}
void
_
handleTapCancel
()
{
void
handleTapCancel
()
{
// longPress arrives after tapCancel, so remember the tap position.
_longPressPosition
=
_lastTapDownPosition
;
_lastTapDownPosition
=
null
;
}
void
_handleTapCancel
()
{
assert
(!
ignorePointer
);
handleTapCancel
();
}
void
_
handleLongPress
()
{
void
handleLongPress
()
{
_layoutText
(
constraints
.
maxWidth
);
final
Offset
globalPosition
=
_longPressPosition
;
_longPressPosition
=
null
;
...
...
@@ -589,6 +612,10 @@ class RenderEditable extends RenderBox {
onSelectionChanged
(
_selectWordAtOffset
(
position
),
this
,
SelectionChangedCause
.
longPress
);
}
}
void
_handleLongPress
()
{
assert
(!
ignorePointer
);
handleLongPress
();
}
TextSelection
_selectWordAtOffset
(
TextPosition
position
)
{
assert
(
_textLayoutLastWidth
==
constraints
.
maxWidth
);
...
...
packages/flutter/lib/src/widgets/editable_text.dart
View file @
27eeb972
...
...
@@ -149,8 +149,8 @@ class EditableText extends StatefulWidget {
/// [TextInputType.text] unless [maxLines] is greater than one, when it will
/// default to [TextInputType.multiline].
///
/// The [controller], [focusNode], [style], [cursorColor],
and [textAlign]
/// arguments must not be null.
/// The [controller], [focusNode], [style], [cursorColor],
[textAlign],
/// a
nd [rendererIgnoresPointer], a
rguments must not be null.
EditableText
({
Key
key
,
@required
this
.
controller
,
...
...
@@ -171,6 +171,7 @@ class EditableText extends StatefulWidget {
this
.
onSubmitted
,
this
.
onSelectionChanged
,
List
<
TextInputFormatter
>
inputFormatters
,
this
.
rendererIgnoresPointer
:
false
,
})
:
assert
(
controller
!=
null
),
assert
(
focusNode
!=
null
),
assert
(
obscureText
!=
null
),
...
...
@@ -180,6 +181,7 @@ class EditableText extends StatefulWidget {
assert
(
textAlign
!=
null
),
assert
(
maxLines
==
null
||
maxLines
>
0
),
assert
(
autofocus
!=
null
),
assert
(
rendererIgnoresPointer
!=
null
),
keyboardType
=
keyboardType
??
(
maxLines
==
1
?
TextInputType
.
text
:
TextInputType
.
multiline
),
inputFormatters
=
maxLines
==
1
?
(
...
...
@@ -279,6 +281,12 @@ class EditableText extends StatefulWidget {
/// in the provided order when the text input changes.
final
List
<
TextInputFormatter
>
inputFormatters
;
/// If true, the [RenderEditable] created by this widget will not handle
/// pointer events, see [renderEditable] and [RenderEditable.ignorePointer].
///
/// This property is false by default.
final
bool
rendererIgnoresPointer
;
@override
EditableTextState
createState
()
=>
new
EditableTextState
();
...
...
@@ -303,6 +311,7 @@ class EditableText extends StatefulWidget {
class
EditableTextState
extends
State
<
EditableText
>
with
AutomaticKeepAliveClientMixin
implements
TextInputClient
{
Timer
_cursorTimer
;
final
ValueNotifier
<
bool
>
_showCursor
=
new
ValueNotifier
<
bool
>(
false
);
final
GlobalKey
_editableKey
=
new
GlobalKey
();
TextInputConnection
_textInputConnection
;
TextSelectionOverlay
_selectionOverlay
;
...
...
@@ -628,6 +637,12 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
return
result
;
}
/// The renderer for this widget's [Editable] descendant.
///
/// This property is typically used to notify the renderer of input gestures
/// when [ignorePointer] is true. See [RenderEditable.ignorePointer].
RenderEditable
get
renderEditable
=>
_editableKey
.
currentContext
.
findRenderObject
();
@override
Widget
build
(
BuildContext
context
)
{
FocusScope
.
of
(
context
).
reparentIfNeeded
(
widget
.
focusNode
);
...
...
@@ -640,6 +655,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
return
new
CompositedTransformTarget
(
link:
_layerLink
,
child:
new
_Editable
(
key:
_editableKey
,
value:
_value
,
style:
widget
.
style
,
cursorColor:
widget
.
cursorColor
,
...
...
@@ -656,6 +672,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
offset:
offset
,
onSelectionChanged:
_handleSelectionChanged
,
onCaretChanged:
_handleCaretChanged
,
rendererIgnoresPointer:
widget
.
rendererIgnoresPointer
,
),
);
},
...
...
@@ -682,7 +699,9 @@ class _Editable extends LeafRenderObjectWidget {
this
.
offset
,
this
.
onSelectionChanged
,
this
.
onCaretChanged
,
this
.
rendererIgnoresPointer
:
false
,
})
:
assert
(
textDirection
!=
null
),
assert
(
rendererIgnoresPointer
!=
null
),
super
(
key:
key
);
final
TextEditingValue
value
;
...
...
@@ -701,6 +720,7 @@ class _Editable extends LeafRenderObjectWidget {
final
ViewportOffset
offset
;
final
SelectionChangedHandler
onSelectionChanged
;
final
CaretChangedHandler
onCaretChanged
;
final
bool
rendererIgnoresPointer
;
@override
RenderEditable
createRenderObject
(
BuildContext
context
)
{
...
...
@@ -718,6 +738,7 @@ class _Editable extends LeafRenderObjectWidget {
offset:
offset
,
onSelectionChanged:
onSelectionChanged
,
onCaretChanged:
onCaretChanged
,
ignorePointer:
rendererIgnoresPointer
,
);
}
...
...
@@ -736,7 +757,8 @@ class _Editable extends LeafRenderObjectWidget {
..
selection
=
value
.
selection
..
offset
=
offset
..
onSelectionChanged
=
onSelectionChanged
..
onCaretChanged
=
onCaretChanged
;
..
onCaretChanged
=
onCaretChanged
..
ignorePointer
=
rendererIgnoresPointer
;
}
TextSpan
get
_styledTextSpan
{
...
...
packages/flutter/test/material/ink_paint_test.dart
View file @
27eeb972
...
...
@@ -140,7 +140,8 @@ void main() {
// At this point the splash radius has expanded to its limit: 5 past the
// ink well's radius parameter. The splash center has moved to its final
// location at the inkwell's center and the fade-out is about to start.
await
tester
.
pump
(
const
Duration
(
milliseconds:
225
));
// The fade-out begins at 225ms = 50ms + 25ms + 150ms.
await
tester
.
pump
(
const
Duration
(
milliseconds:
150
));
expect
(
box
,
paints
..
something
((
Symbol
method
,
List
<
dynamic
>
arguments
)
{
if
(
method
!=
#drawCircle
)
return
false
;
...
...
packages/flutter/test/material/text_field_splash_test.dart
0 → 100644
View file @
27eeb972
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/rendering.dart'
;
int
confirmCount
=
0
;
int
cancelCount
=
0
;
class
TestInkSplash
extends
InkSplash
{
TestInkSplash
({
MaterialInkController
controller
,
RenderBox
referenceBox
,
Offset
position
,
Color
color
,
bool
containedInkWell:
false
,
RectCallback
rectCallback
,
BorderRadius
borderRadius
,
double
radius
,
VoidCallback
onRemoved
,
})
:
super
(
controller:
controller
,
referenceBox:
referenceBox
,
position:
position
,
color:
color
,
containedInkWell:
containedInkWell
,
rectCallback:
rectCallback
,
borderRadius:
borderRadius
,
radius:
radius
,
onRemoved:
onRemoved
,
);
@override
void
confirm
()
{
confirmCount
+=
1
;
super
.
confirm
();
}
@override
void
cancel
()
{
cancelCount
+=
1
;
super
.
cancel
();
}
}
class
TestInkSplashFactory
extends
InteractiveInkFeatureFactory
{
const
TestInkSplashFactory
();
@override
InteractiveInkFeature
create
({
MaterialInkController
controller
,
RenderBox
referenceBox
,
Offset
position
,
Color
color
,
bool
containedInkWell:
false
,
RectCallback
rectCallback
,
BorderRadius
borderRadius
,
double
radius
,
VoidCallback
onRemoved
,
})
{
return
new
TestInkSplash
(
controller:
controller
,
referenceBox:
referenceBox
,
position:
position
,
color:
color
,
containedInkWell:
containedInkWell
,
rectCallback:
rectCallback
,
borderRadius:
borderRadius
,
radius:
radius
,
onRemoved:
onRemoved
,
);
}
}
void
main
(
)
{
testWidgets
(
'Tap and no focus causes a splash'
,
(
WidgetTester
tester
)
async
{
final
Key
textField1
=
new
UniqueKey
();
final
Key
textField2
=
new
UniqueKey
();
await
tester
.
pumpWidget
(
new
MaterialApp
(
home:
new
Theme
(
data:
new
ThemeData
.
light
().
copyWith
(
splashFactory:
const
TestInkSplashFactory
()),
child:
new
Material
(
child:
new
Container
(
alignment:
Alignment
.
topLeft
,
child:
new
Column
(
children:
<
Widget
>[
new
TextField
(
key:
textField1
,
decoration:
const
InputDecoration
(
labelText:
'label'
,
),
),
new
TextField
(
key:
textField2
,
decoration:
const
InputDecoration
(
labelText:
'label'
,
),
),
],
),
),
),
),
)
);
confirmCount
=
0
;
cancelCount
=
0
;
await
tester
.
tap
(
find
.
byKey
(
textField1
));
await
tester
.
pumpAndSettle
();
expect
(
confirmCount
,
1
);
expect
(
cancelCount
,
0
);
// textField1 already has the focus, no new splash
await
tester
.
tap
(
find
.
byKey
(
textField1
));
await
tester
.
pumpAndSettle
();
expect
(
confirmCount
,
1
);
expect
(
cancelCount
,
0
);
// textField2 gets the focus and a splash
await
tester
.
tap
(
find
.
byKey
(
textField2
));
await
tester
.
pumpAndSettle
();
expect
(
confirmCount
,
2
);
expect
(
cancelCount
,
0
);
// Tap outside of textField1's editable. It still gets focus and splash.
await
tester
.
tapAt
(
tester
.
getTopLeft
(
find
.
byKey
(
textField1
)));
await
tester
.
pumpAndSettle
();
expect
(
confirmCount
,
3
);
expect
(
cancelCount
,
0
);
// Tap in the center of textField2's editable. It still gets the focus
// and the splash. There is no splash cancel.
await
tester
.
tap
(
find
.
byKey
(
textField2
));
await
tester
.
pumpAndSettle
();
expect
(
confirmCount
,
4
);
expect
(
cancelCount
,
0
);
});
testWidgets
(
'Splash cancel'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
new
MaterialApp
(
home:
new
Theme
(
data:
new
ThemeData
.
light
().
copyWith
(
splashFactory:
const
TestInkSplashFactory
()),
child:
new
Material
(
child:
new
ListView
(
children:
<
Widget
>[
const
TextField
(
decoration:
const
InputDecoration
(
labelText:
'label1'
,
),
),
const
TextField
(
decoration:
const
InputDecoration
(
labelText:
'label2'
,
),
),
new
Container
(
height:
1000.0
,
color:
const
Color
(
0xFF00FF00
),
),
],
),
),
),
)
);
confirmCount
=
0
;
cancelCount
=
0
;
// Pointer is dragged below the textfield, splash is canceled.
final
TestGesture
gesture1
=
await
tester
.
startGesture
(
tester
.
getCenter
(
find
.
text
(
'label1'
)));
await
tester
.
pumpAndSettle
();
await
gesture1
.
moveTo
(
const
Offset
(
400.0
,
300.0
));
await
gesture1
.
up
();
expect
(
confirmCount
,
0
);
expect
(
cancelCount
,
1
);
// Pointer is dragged upwards causing a scroll, splash is canceled.
final
TestGesture
gesture2
=
await
tester
.
startGesture
(
tester
.
getCenter
(
find
.
text
(
'label2'
)));
await
tester
.
pumpAndSettle
();
await
gesture2
.
moveBy
(
const
Offset
(
0.0
,
-
200.0
),
timeStamp:
const
Duration
(
milliseconds:
32
));
await
gesture2
.
up
();
expect
(
confirmCount
,
0
);
expect
(
cancelCount
,
2
);
});
}
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