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
d3f1a3ce
Unverified
Commit
d3f1a3ce
authored
Sep 15, 2021
by
nt4f04uNd
Committed by
GitHub
Sep 15, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
RefreshProgressIndicator to look native (#88301)
parent
3a3e709c
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
149 additions
and
23 deletions
+149
-23
progress_indicator.dart
packages/flutter/lib/src/material/progress_indicator.dart
+90
-20
refresh_indicator.dart
packages/flutter/lib/src/material/refresh_indicator.dart
+1
-1
progress_indicator_test.dart
packages/flutter/test/material/progress_indicator_test.dart
+56
-0
refresh_indicator_test.dart
packages/flutter/test/material/refresh_indicator_test.dart
+2
-2
No files found.
packages/flutter/lib/src/material/progress_indicator.dart
View file @
d3f1a3ce
...
...
@@ -696,7 +696,7 @@ class _RefreshProgressIndicatorPainter extends _CircularProgressIndicatorPainter
final
double
radius
=
size
.
width
/
2.0
;
final
double
arrowheadPointX
=
radius
+
ux
*
radius
+
-
uy
*
strokeWidth
*
2.0
*
arrowheadScale
;
final
double
arrowheadPointY
=
radius
+
uy
*
radius
+
ux
*
strokeWidth
*
2.0
*
arrowheadScale
;
final
double
arrowheadRadius
=
strokeWidth
*
1.5
*
arrowheadScale
;
final
double
arrowheadRadius
=
strokeWidth
*
2.0
*
arrowheadScale
;
final
double
innerRadius
=
radius
-
arrowheadRadius
;
final
double
outerRadius
=
radius
+
arrowheadRadius
;
...
...
@@ -746,7 +746,7 @@ class RefreshProgressIndicator extends CircularProgressIndicator {
Color
?
backgroundColor
,
Color
?
color
,
Animation
<
Color
?>?
valueColor
,
double
strokeWidth
=
2.0
,
// Different default than CircularProgressIndicator.
double
strokeWidth
=
defaultStrokeWidth
,
// Different default than CircularProgressIndicator.
String
?
semanticsLabel
,
String
?
semanticsValue
,
})
:
super
(
...
...
@@ -760,6 +760,9 @@ class RefreshProgressIndicator extends CircularProgressIndicator {
semanticsValue:
semanticsValue
,
);
/// Default stroke width.
static
const
double
defaultStrokeWidth
=
2.5
;
/// {@template flutter.material.RefreshProgressIndicator.backgroundColor}
/// Background color of that fills the circle under the refresh indicator.
///
...
...
@@ -770,33 +773,94 @@ class RefreshProgressIndicator extends CircularProgressIndicator {
/// {@endtemplate}
@override
Color
?
get
backgroundColor
=>
super
.
backgroundColor
;
@override
State
<
CircularProgressIndicator
>
createState
()
=>
_RefreshProgressIndicatorState
();
}
class
_RefreshProgressIndicatorState
extends
_CircularProgressIndicatorState
{
static
const
double
_indicatorSize
=
40.0
;
static
const
double
_indicatorSize
=
41.0
;
/// Interval for arrow head to fully grow.
static
const
double
_strokeHeadInterval
=
0.33
;
late
final
Animatable
<
double
>
_convertTween
=
CurveTween
(
curve:
const
Interval
(
0.1
,
_strokeHeadInterval
),
);
late
final
Animatable
<
double
>
_additionalRotationTween
=
TweenSequence
<
double
>(
<
TweenSequenceItem
<
double
>>[
// Makes arrow to expand a little bit earlier, to match the Android look.
TweenSequenceItem
<
double
>(
tween:
Tween
<
double
>(
begin:
-
0.1
,
end:
-
0.2
),
weight:
_strokeHeadInterval
,
),
// Additional rotation after the arrow expanded
TweenSequenceItem
<
double
>(
tween:
Tween
<
double
>(
begin:
-
0.2
,
end:
1.35
),
weight:
1
-
_strokeHeadInterval
,
),
],
);
// Last value received from the widget before null.
double
?
_lastValue
;
// Always show the indeterminate version of the circular progress indicator.
//
// When value is non-null the sweep of the progress indicator arrow's arc
// varies from 0 to about 270 degrees. When value is null the arrow animates
// starting from wherever we left it.
// varies from 0 to about 300 degrees.
//
// When value is null the arrow animation starting from wherever we left it.
@override
Widget
build
(
BuildContext
context
)
{
if
(
widget
.
value
!=
null
)
_controller
.
value
=
widget
.
value
!
*
(
1333
/
2
/
_kIndeterminateCircularDuration
);
else
if
(!
_controller
.
isAnimating
)
_controller
.
repeat
();
final
double
?
value
=
widget
.
value
;
if
(
value
!=
null
)
{
_lastValue
=
value
;
_controller
.
value
=
_convertTween
.
transform
(
value
)
*
(
1333
/
2
/
_kIndeterminateCircularDuration
);
}
return
_buildAnimation
();
}
@override
Widget
_buildAnimation
()
{
return
AnimatedBuilder
(
animation:
_controller
,
builder:
(
BuildContext
context
,
Widget
?
child
)
{
return
_buildMaterialIndicator
(
context
,
// Lengthen the arc a little
1.05
*
_CircularProgressIndicatorState
.
_strokeHeadTween
.
evaluate
(
_controller
),
_CircularProgressIndicatorState
.
_strokeTailTween
.
evaluate
(
_controller
),
_CircularProgressIndicatorState
.
_offsetTween
.
evaluate
(
_controller
),
_CircularProgressIndicatorState
.
_rotationTween
.
evaluate
(
_controller
),
);
},
);
}
@override
Widget
_buildMaterialIndicator
(
BuildContext
context
,
double
headValue
,
double
tailValue
,
double
offsetValue
,
double
rotationValue
)
{
final
double
arrowheadScale
=
widget
.
value
==
null
?
0.0
:
(
widget
.
value
!
*
2.0
).
clamp
(
0.0
,
1.0
);
final
double
?
value
=
widget
.
value
;
final
double
arrowheadScale
=
value
==
null
?
0.0
:
const
Interval
(
0.1
,
_strokeHeadInterval
).
transform
(
value
);
final
double
rotation
;
if
(
value
==
null
&&
_lastValue
==
null
)
{
rotation
=
0.0
;
}
else
{
rotation
=
math
.
pi
*
_additionalRotationTween
.
transform
(
value
??
_lastValue
!);
}
Color
valueColor
=
widget
.
_getValueColor
(
context
);
final
double
opacity
=
valueColor
.
opacity
;
valueColor
=
valueColor
.
withOpacity
(
1.0
);
final
Color
backgroundColor
=
widget
.
backgroundColor
??
ProgressIndicatorTheme
.
of
(
context
).
refreshBackgroundColor
??
Theme
.
of
(
context
).
canvasColor
;
return
widget
.
_buildSemanticsWrapper
(
context:
context
,
child:
Container
(
...
...
@@ -809,9 +873,13 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState {
elevation:
2.0
,
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
12.0
),
child:
Opacity
(
opacity:
opacity
,
child:
Transform
.
rotate
(
angle:
rotation
,
child:
CustomPaint
(
painter:
_RefreshProgressIndicatorPainter
(
valueColor:
widget
.
_getValueColor
(
context
)
,
valueColor:
valueColor
,
value:
null
,
// Draw the indeterminate progress indicator.
headValue:
headValue
,
tailValue:
tailValue
,
...
...
@@ -824,6 +892,8 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState {
),
),
),
),
),
);
}
}
packages/flutter/lib/src/material/refresh_indicator.dart
View file @
d3f1a3ce
...
...
@@ -120,7 +120,7 @@ class RefreshIndicator extends StatefulWidget {
this
.
notificationPredicate
=
defaultScrollNotificationPredicate
,
this
.
semanticsLabel
,
this
.
semanticsValue
,
this
.
strokeWidth
=
2.0
,
this
.
strokeWidth
=
RefreshProgressIndicator
.
defaultStrokeWidth
,
this
.
triggerMode
=
RefreshIndicatorTriggerMode
.
onEdge
,
})
:
assert
(
child
!=
null
),
assert
(
onRefresh
!=
null
),
...
...
packages/flutter/test/material/progress_indicator_test.dart
View file @
d3f1a3ce
...
...
@@ -534,6 +534,19 @@ void main() {
expect
(
tester
.
hasRunningAnimations
,
isTrue
);
});
testWidgets
(
'RefreshProgressIndicator uses expected animation'
,
(
WidgetTester
tester
)
async
{
final
AnimationSheetBuilder
animationSheet
=
AnimationSheetBuilder
(
frameSize:
const
Size
(
50
,
50
));
await
tester
.
pumpFrames
(
animationSheet
.
record
(
const
_RefreshProgressIndicatorGolden
(),
),
const
Duration
(
seconds:
3
));
await
expectLater
(
await
animationSheet
.
collate
(
20
),
matchesGoldenFile
(
'material.refresh_progress_indicator.png'
),
);
},
skip:
isBrowser
);
// https://github.com/flutter/flutter/issues/56001
testWidgets
(
'Determinate CircularProgressIndicator stops the animator'
,
(
WidgetTester
tester
)
async
{
double
?
progressValue
;
late
StateSetter
setState
;
...
...
@@ -863,3 +876,46 @@ void main() {
expect
((
wrappedTheme
as
ProgressIndicatorTheme
).
data
,
themeData
);
});
}
class
_RefreshProgressIndicatorGolden
extends
StatefulWidget
{
const
_RefreshProgressIndicatorGolden
({
Key
?
key
})
:
super
(
key:
key
);
@override
_RefreshProgressIndicatorGoldenState
createState
()
=>
_RefreshProgressIndicatorGoldenState
();
}
class
_RefreshProgressIndicatorGoldenState
extends
State
<
_RefreshProgressIndicatorGolden
>
with
SingleTickerProviderStateMixin
{
late
final
AnimationController
controller
=
AnimationController
(
vsync:
this
,
duration:
const
Duration
(
seconds:
1
),
)
..
forward
()
..
addListener
(()
{
setState
(()
{});
})
..
addStatusListener
((
AnimationStatus
status
)
{
if
(
status
==
AnimationStatus
.
completed
)
{
indeterminate
=
true
;
}
});
bool
indeterminate
=
false
;
@override
void
dispose
()
{
controller
.
dispose
();
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
Center
(
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
RefreshProgressIndicator
(
value:
indeterminate
?
null
:
controller
.
value
,
),
),
);
}
}
packages/flutter/test/material/refresh_indicator_test.dart
View file @
d3f1a3ce
...
...
@@ -470,10 +470,10 @@ void main() {
),
);
//
By default the value of strokeWidth is 2.0
//
Check for the default value
expect
(
tester
.
widget
<
RefreshIndicator
>(
find
.
byType
(
RefreshIndicator
)).
strokeWidth
,
2.0
,
RefreshProgressIndicator
.
defaultStrokeWidth
,
);
await
tester
.
pumpWidget
(
...
...
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