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
236acb52
Unverified
Commit
236acb52
authored
Jul 10, 2018
by
Natalie Sampsell
Committed by
GitHub
Jul 10, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Segmented control animation (#18811)
Added animation to segmented control widget.
parent
03a1f4ac
Changes
2
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
722 additions
and
327 deletions
+722
-327
segmented_control.dart
packages/flutter/lib/src/cupertino/segmented_control.dart
+154
-29
segmented_control_test.dart
packages/flutter/test/cupertino/segmented_control_test.dart
+568
-298
No files found.
packages/flutter/lib/src/cupertino/segmented_control.dart
View file @
236acb52
...
...
@@ -23,6 +23,10 @@ const double _kMinSegmentedControlHeight = 28.0;
// press or drag.
const
Color
_kPressedBackground
=
const
Color
(
0x33007aff
);
// The duration of the fade animation used to transition when a new widget
// is selected.
const
Duration
_kFadeDuration
=
const
Duration
(
milliseconds:
165
);
/// An iOS-style segmented control.
///
/// Displays the widgets provided in the [Map] of [children] in a
...
...
@@ -147,20 +151,69 @@ class SegmentedControl<T> extends StatefulWidget {
_SegmentedControlState
<
T
>
createState
()
=>
_SegmentedControlState
<
T
>();
}
class
_SegmentedControlState
<
T
>
extends
State
<
SegmentedControl
<
T
>>
{
class
_SegmentedControlState
<
T
>
extends
State
<
SegmentedControl
<
T
>>
with
TickerProviderStateMixin
<
SegmentedControl
<
T
>>
{
T
_pressedKey
;
void
_onTapDown
(
T
currentKey
)
{
final
List
<
AnimationController
>
_selectionControllers
=
<
AnimationController
>[];
final
List
<
ColorTween
>
_childTweens
=
<
ColorTween
>[];
static
final
ColorTween
forwardBackgroundColorTween
=
new
ColorTween
(
begin:
_kPressedBackground
,
end:
CupertinoColors
.
activeBlue
,
);
static
final
ColorTween
reverseBackgroundColorTween
=
new
ColorTween
(
begin:
CupertinoColors
.
white
,
end:
CupertinoColors
.
activeBlue
,
);
static
final
ColorTween
textColorTween
=
new
ColorTween
(
begin:
CupertinoColors
.
activeBlue
,
end:
CupertinoColors
.
white
,
);
@override
void
initState
()
{
super
.
initState
();
for
(
T
key
in
widget
.
children
.
keys
)
{
final
AnimationController
animationController
=
createAnimationController
();
if
(
widget
.
groupValue
==
key
)
{
_childTweens
.
add
(
reverseBackgroundColorTween
);
animationController
.
value
=
1.0
;
}
else
{
_childTweens
.
add
(
forwardBackgroundColorTween
);
}
_selectionControllers
.
add
(
animationController
);
}
}
AnimationController
createAnimationController
()
{
return
new
AnimationController
(
duration:
_kFadeDuration
,
vsync:
this
,
)..
addListener
(()
{
setState
(()
{
_pressedKey
=
currentKey
;
// State of background/text colors has changed
});
});
}
void
_onTapUp
(
TapUpDetails
event
)
{
@override
void
dispose
()
{
for
(
AnimationController
animationController
in
_selectionControllers
)
{
animationController
.
dispose
();
}
super
.
dispose
();
}
void
_onTapDown
(
T
currentKey
)
{
if
(
_pressedKey
==
null
&&
currentKey
!=
widget
.
groupValue
)
{
setState
(()
{
_pressedKey
=
null
;
_pressedKey
=
currentKey
;
});
}
}
void
_onTapCancel
()
{
setState
(()
{
...
...
@@ -169,14 +222,69 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
}
void
_onTap
(
T
currentKey
)
{
if
(
currentKey
!=
widget
.
groupValue
)
{
if
(
currentKey
!=
widget
.
groupValue
&&
currentKey
==
_pressedKey
)
{
widget
.
onValueChanged
(
currentKey
);
_pressedKey
=
null
;
}
}
Color
getTextColor
(
int
index
,
T
currentKey
)
{
if
(
_selectionControllers
[
index
].
isAnimating
)
return
textColorTween
.
evaluate
(
_selectionControllers
[
index
]);
if
(
widget
.
groupValue
==
currentKey
)
return
CupertinoColors
.
white
;
return
CupertinoColors
.
activeBlue
;
}
Color
getBackgroundColor
(
int
index
,
T
currentKey
)
{
if
(
_selectionControllers
[
index
].
isAnimating
)
return
_childTweens
[
index
].
evaluate
(
_selectionControllers
[
index
]);
if
(
widget
.
groupValue
==
currentKey
)
return
CupertinoColors
.
activeBlue
;
if
(
_pressedKey
==
currentKey
)
return
_kPressedBackground
;
return
CupertinoColors
.
white
;
}
void
updateAnimationControllers
()
{
if
(
_selectionControllers
.
length
>
widget
.
children
.
length
)
{
_selectionControllers
.
length
=
widget
.
children
.
length
;
_childTweens
.
length
=
widget
.
children
.
length
;
}
else
{
for
(
int
index
=
_selectionControllers
.
length
;
index
<
widget
.
children
.
length
;
index
+=
1
)
{
_selectionControllers
.
add
(
createAnimationController
());
_childTweens
.
add
(
reverseBackgroundColorTween
);
}
}
}
@override
void
didUpdateWidget
(
SegmentedControl
<
T
>
oldWidget
)
{
super
.
didUpdateWidget
(
oldWidget
);
if
(
oldWidget
.
children
.
length
!=
widget
.
children
.
length
)
{
updateAnimationControllers
();
}
if
(
oldWidget
.
groupValue
!=
widget
.
groupValue
)
{
int
index
=
0
;
for
(
T
key
in
widget
.
children
.
keys
)
{
if
(
widget
.
groupValue
==
key
)
{
_childTweens
[
index
]
=
forwardBackgroundColorTween
;
_selectionControllers
[
index
].
forward
();
}
else
{
_childTweens
[
index
]
=
reverseBackgroundColorTween
;
_selectionControllers
[
index
].
reverse
();
}
index
+=
1
;
}
}
}
@override
Widget
build
(
BuildContext
context
)
{
final
List
<
Widget
>
gestureChildren
=
<
Widget
>[];
final
List
<
Widget
>
_gestureChildren
=
<
Widget
>[];
final
List
<
Color
>
_backgroundColors
=
<
Color
>[];
int
index
=
0
;
int
selectedIndex
;
int
pressedIndex
;
...
...
@@ -185,12 +293,10 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
pressedIndex
=
(
_pressedKey
==
currentKey
)
?
index
:
pressedIndex
;
final
TextStyle
textStyle
=
DefaultTextStyle
.
of
(
context
).
style
.
copyWith
(
color:
(
widget
.
groupValue
==
currentKey
)
?
CupertinoColors
.
white
:
CupertinoColors
.
activeBlue
,
color:
getTextColor
(
index
,
currentKey
),
);
final
IconThemeData
iconTheme
=
new
IconThemeData
(
color:
(
widget
.
groupValue
==
currentKey
)
?
CupertinoColors
.
white
:
CupertinoColors
.
activeBlue
,
color:
getTextColor
(
index
,
currentKey
),
);
Widget
child
=
widget
.
children
[
currentKey
];
...
...
@@ -198,7 +304,6 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
onTapDown:
(
TapDownDetails
event
)
{
_onTapDown
(
currentKey
);
},
onTapUp:
_onTapUp
,
onTapCancel:
_onTapCancel
,
onTap:
()
{
_onTap
(
currentKey
);
...
...
@@ -215,14 +320,17 @@ class _SegmentedControlState<T> extends State<SegmentedControl<T>> {
),
),
);
gestureChildren
.
add
(
child
);
_backgroundColors
.
add
(
getBackgroundColor
(
index
,
currentKey
));
_gestureChildren
.
add
(
child
);
index
+=
1
;
}
final
Widget
box
=
new
_SegmentedControlRenderWidget
<
T
>(
children:
gestureChildren
,
children:
_
gestureChildren
,
selectedIndex:
selectedIndex
,
pressedIndex:
pressedIndex
,
backgroundColors:
_backgroundColors
,
);
return
new
Padding
(
...
...
@@ -241,6 +349,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
List
<
Widget
>
children
=
const
<
Widget
>[],
@required
this
.
selectedIndex
,
@required
this
.
pressedIndex
,
@required
this
.
backgroundColors
,
})
:
super
(
key:
key
,
children:
children
,
...
...
@@ -248,6 +357,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
final
int
selectedIndex
;
final
int
pressedIndex
;
final
List
<
Color
>
backgroundColors
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
...
...
@@ -255,6 +365,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
textDirection:
Directionality
.
of
(
context
),
selectedIndex:
selectedIndex
,
pressedIndex:
pressedIndex
,
backgroundColors:
backgroundColors
,
);
}
...
...
@@ -263,7 +374,8 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
renderObject
..
textDirection
=
Directionality
.
of
(
context
)
..
selectedIndex
=
selectedIndex
..
pressedIndex
=
pressedIndex
;
..
pressedIndex
=
pressedIndex
..
backgroundColors
=
backgroundColors
;
}
}
...
...
@@ -281,10 +393,12 @@ class _RenderSegmentedControl<T> extends RenderBox
@required
int
selectedIndex
,
@required
int
pressedIndex
,
@required
TextDirection
textDirection
,
@required
List
<
Color
>
backgroundColors
,
})
:
assert
(
textDirection
!=
null
),
_textDirection
=
textDirection
,
_selectedIndex
=
selectedIndex
,
_pressedIndex
=
pressedIndex
{
_pressedIndex
=
pressedIndex
,
_backgroundColors
=
backgroundColors
{
addAll
(
children
);
}
...
...
@@ -318,6 +432,16 @@ class _RenderSegmentedControl<T> extends RenderBox
markNeedsLayout
();
}
List
<
Color
>
get
backgroundColors
=>
_backgroundColors
;
List
<
Color
>
_backgroundColors
;
set
backgroundColors
(
List
<
Color
>
value
)
{
if
(
_backgroundColors
==
value
)
{
return
;
}
_backgroundColors
=
value
;
markNeedsPaint
();
}
final
Paint
_outlinePaint
=
new
Paint
()
..
color
=
CupertinoColors
.
activeBlue
..
strokeWidth
=
1.0
...
...
@@ -481,17 +605,10 @@ class _RenderSegmentedControl<T> extends RenderBox
final
_SegmentedControlContainerBoxParentData
childParentData
=
child
.
parentData
;
Color
color
=
CupertinoColors
.
white
;
if
(
selectedIndex
!=
null
&&
selectedIndex
==
childIndex
)
{
color
=
CupertinoColors
.
activeBlue
;
}
else
if
(
pressedIndex
!=
null
&&
pressedIndex
==
childIndex
)
{
color
=
_kPressedBackground
;
}
context
.
canvas
.
drawRRect
(
childParentData
.
surroundingRect
.
shift
(
offset
),
new
Paint
()
..
color
=
color
..
color
=
backgroundColors
[
childIndex
]
..
style
=
PaintingStyle
.
fill
,
);
context
.
canvas
.
drawRRect
(
...
...
@@ -505,6 +622,14 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
bool
hitTestChildren
(
HitTestResult
result
,
{
@required
Offset
position
})
{
assert
(
position
!=
null
);
return
defaultHitTestChildren
(
result
,
position:
position
);
RenderBox
child
=
lastChild
;
while
(
child
!=
null
)
{
final
_SegmentedControlContainerBoxParentData
childParentData
=
child
.
parentData
;
if
(
childParentData
.
surroundingRect
.
contains
(
position
))
{
return
child
.
hitTest
(
result
,
position:
(
Offset
.
zero
&
child
.
size
).
center
);
}
child
=
childParentData
.
previousSibling
;
}
return
false
;
}
}
packages/flutter/test/cupertino/segmented_control_test.dart
View file @
236acb52
This diff is collapsed.
Click to expand it.
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