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
92d0445a
Commit
92d0445a
authored
Aug 04, 2016
by
Matt Perry
Committed by
GitHub
Aug 04, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add a fade-in animation for the text selection controls. (#5190)
BUG=
https://github.com/flutter/flutter/issues/3938
parent
40d26f43
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
94 additions
and
12 deletions
+94
-12
editable.dart
packages/flutter/lib/src/widgets/editable.dart
+1
-1
text_selection.dart
packages/flutter/lib/src/widgets/text_selection.dart
+39
-11
input_test.dart
packages/flutter/test/widget/input_test.dart
+54
-0
No files found.
packages/flutter/lib/src/widgets/editable.dart
View file @
92d0445a
...
...
@@ -389,7 +389,7 @@ class RawInputLineState extends ScrollableState<RawInputLine> {
if
(
_cursorTimer
!=
null
)
_stopCursorTimer
();
scheduleMicrotask
(()
{
// can't hide while disposing, since it triggers a rebuild
_selectionOverlay
?.
hid
e
();
_selectionOverlay
?.
dispos
e
();
});
super
.
dispose
();
}
...
...
packages/flutter/lib/src/widgets/text_selection.dart
View file @
92d0445a
...
...
@@ -11,6 +11,7 @@ import 'editable.dart';
import
'framework.dart'
;
import
'gesture_detector.dart'
;
import
'overlay.dart'
;
import
'transitions.dart'
;
// TODO(mpcomplete): Need one for [collapsed].
/// Which type of selection handle to be displayed.
...
...
@@ -114,6 +115,13 @@ class TextSelectionOverlay implements TextSelectionDelegate {
/// The tool bar typically contains buttons for copying and pasting text.
final
TextSelectionToolbarBuilder
toolbarBuilder
;
/// Controls the fade-in animations.
static
const
Duration
_kFadeDuration
=
const
Duration
(
milliseconds:
150
);
final
AnimationController
_handleController
=
new
AnimationController
(
duration:
_kFadeDuration
);
final
AnimationController
_toolbarController
=
new
AnimationController
(
duration:
_kFadeDuration
);
Animation
<
double
>
get
_handleOpacity
=>
_handleController
.
view
;
Animation
<
double
>
get
_toolbarOpacity
=>
_toolbarController
.
view
;
InputValue
_input
;
/// A pair of handles. If this is non-null, there are always 2, though the
...
...
@@ -129,10 +137,11 @@ class TextSelectionOverlay implements TextSelectionDelegate {
void
showHandles
()
{
assert
(
_handles
==
null
);
_handles
=
<
OverlayEntry
>[
new
OverlayEntry
(
builder:
(
BuildContext
c
)
=>
_build
Overlay
(
c
,
_TextSelectionHandlePosition
.
start
)),
new
OverlayEntry
(
builder:
(
BuildContext
c
)
=>
_build
Overlay
(
c
,
_TextSelectionHandlePosition
.
end
)),
new
OverlayEntry
(
builder:
(
BuildContext
c
)
=>
_build
Handle
(
c
,
_TextSelectionHandlePosition
.
start
)),
new
OverlayEntry
(
builder:
(
BuildContext
c
)
=>
_build
Handle
(
c
,
_TextSelectionHandlePosition
.
end
)),
];
Overlay
.
of
(
context
,
debugRequiredFor:
debugRequiredFor
).
insertAll
(
_handles
);
_handleController
.
forward
(
from:
0.0
);
}
/// Shows the toolbar by inserting it into the [context]'s overlay.
...
...
@@ -140,6 +149,7 @@ class TextSelectionOverlay implements TextSelectionDelegate {
assert
(
_toolbar
==
null
);
_toolbar
=
new
OverlayEntry
(
builder:
_buildToolbar
);
Overlay
.
of
(
context
,
debugRequiredFor:
debugRequiredFor
).
insert
(
_toolbar
);
_toolbarController
.
forward
(
from:
0.0
);
}
/// Updates the overlay after the [selection] has changed.
...
...
@@ -164,19 +174,33 @@ class TextSelectionOverlay implements TextSelectionDelegate {
}
_toolbar
?.
remove
();
_toolbar
=
null
;
_handleController
.
stop
();
_toolbarController
.
stop
();
}
/// Final cleanup.
void
dispose
()
{
hide
();
_handleController
.
dispose
();
_toolbarController
.
dispose
();
}
Widget
_build
Overlay
(
BuildContext
context
,
_TextSelectionHandlePosition
position
)
{
Widget
_build
Handle
(
BuildContext
context
,
_TextSelectionHandlePosition
position
)
{
if
((
_selection
.
isCollapsed
&&
position
==
_TextSelectionHandlePosition
.
end
)
||
handleBuilder
==
null
)
return
new
Container
();
// hide the second handle when collapsed
return
new
_TextSelectionHandleOverlay
(
onSelectionHandleChanged:
_handleSelectionHandleChanged
,
onSelectionHandleTapped:
_handleSelectionHandleTapped
,
renderObject:
renderObject
,
selection:
_selection
,
builder:
handleBuilder
,
position:
position
return
new
FadeTransition
(
opacity:
_handleOpacity
,
child:
new
_TextSelectionHandleOverlay
(
onSelectionHandleChanged:
_handleSelectionHandleChanged
,
onSelectionHandleTapped:
_handleSelectionHandleTapped
,
renderObject:
renderObject
,
selection:
_selection
,
builder:
handleBuilder
,
position:
position
)
);
}
...
...
@@ -193,7 +217,10 @@ class TextSelectionOverlay implements TextSelectionDelegate {
endpoints
[
0
].
point
.
y
-
renderObject
.
size
.
height
);
return
toolbarBuilder
(
context
,
midpoint
,
this
);
return
new
FadeTransition
(
opacity:
_toolbarOpacity
,
child:
toolbarBuilder
(
context
,
midpoint
,
this
)
);
}
void
_handleSelectionHandleChanged
(
TextSelection
newSelection
)
{
...
...
@@ -252,6 +279,7 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
class
_TextSelectionHandleOverlayState
extends
State
<
_TextSelectionHandleOverlay
>
{
Point
_dragPosition
;
void
_handleDragStart
(
DragStartDetails
details
)
{
_dragPosition
=
details
.
globalPosition
;
}
...
...
packages/flutter/test/widget/input_test.dart
View file @
92d0445a
...
...
@@ -382,4 +382,58 @@ void main() {
await
tester
.
pumpWidget
(
builder
());
expect
(
inputValue
.
text
,
'abc d
${testValue}
ef ghi'
);
});
testWidgets
(
'Selection toolbar fades in'
,
(
WidgetTester
tester
)
async
{
GlobalKey
inputKey
=
new
GlobalKey
();
InputValue
inputValue
=
InputValue
.
empty
;
Widget
builder
()
{
return
new
Overlay
(
initialEntries:
<
OverlayEntry
>[
new
OverlayEntry
(
builder:
(
BuildContext
context
)
{
return
new
Center
(
child:
new
Material
(
child:
new
Input
(
value:
inputValue
,
key:
inputKey
,
onChanged:
(
InputValue
value
)
{
inputValue
=
value
;
}
)
)
);
}
)
]
);
}
await
tester
.
pumpWidget
(
builder
());
String
testValue
=
'abc def ghi'
;
enterText
(
testValue
);
await
tester
.
pumpWidget
(
builder
());
// Tap the selection handle to bring up the "paste / select all" menu.
await
tester
.
tapAt
(
textOffsetToPosition
(
tester
,
testValue
.
indexOf
(
'e'
)));
await
tester
.
pumpWidget
(
builder
());
RenderEditableLine
renderLine
=
findRenderEditableLine
(
tester
);
List
<
TextSelectionPoint
>
endpoints
=
renderLine
.
getEndpointsForSelection
(
inputValue
.
selection
);
await
tester
.
tapAt
(
endpoints
[
0
].
point
+
new
Offset
(
1.0
,
1.0
));
await
tester
.
pumpWidget
(
builder
());
// Toolbar should fade in. Starting at 0% opacity.
Element
target
=
tester
.
element
(
find
.
text
(
'SELECT ALL'
));
Opacity
opacity
=
target
.
ancestorWidgetOfExactType
(
Opacity
);
expect
(
opacity
,
isNotNull
);
expect
(
opacity
.
opacity
,
equals
(
0.0
));
// Still fading in.
await
tester
.
pump
(
const
Duration
(
milliseconds:
50
));
opacity
=
target
.
ancestorWidgetOfExactType
(
Opacity
);
expect
(
opacity
.
opacity
,
greaterThan
(
0.0
));
expect
(
opacity
.
opacity
,
lessThan
(
1.0
));
// End the test here to ensure the animation is properly disposed of.
});
}
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