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
107cbd31
Commit
107cbd31
authored
Jun 30, 2016
by
Hans Muller
Committed by
GitHub
Jun 30, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refresh Indicator fine tuning (#4800)
parent
6298a1ae
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
113 additions
and
54 deletions
+113
-54
progress_indicator.dart
packages/flutter/lib/src/material/progress_indicator.dart
+16
-8
refresh_indicator.dart
packages/flutter/lib/src/material/refresh_indicator.dart
+97
-46
No files found.
packages/flutter/lib/src/material/progress_indicator.dart
View file @
107cbd31
...
...
@@ -381,7 +381,8 @@ class _RefreshProgressIndicatorPainter extends _CircularProgressIndicatorPainter
double
tailValue
,
int
stepValue
,
double
rotationValue
,
double
strokeWidth
double
strokeWidth
,
this
.
arrowheadScale
})
:
super
(
valueColor:
valueColor
,
value:
value
,
...
...
@@ -392,23 +393,27 @@ class _RefreshProgressIndicatorPainter extends _CircularProgressIndicatorPainter
strokeWidth:
strokeWidth
);
final
double
arrowheadScale
;
void
paintArrowhead
(
Canvas
canvas
,
Size
size
)
{
// ux, uy: a unit vector whose direction parallels the base of the arrowhead.
// Note that
-ux,
uy points in the direction the arrowhead points.
// Note that
ux, -
uy points in the direction the arrowhead points.
final
double
arcEnd
=
arcStart
+
arcSweep
;
final
double
ux
=
math
.
cos
(
arcEnd
);
final
double
uy
=
math
.
sin
(
arcEnd
);
assert
(
size
.
width
==
size
.
height
);
final
double
radius
=
size
.
width
/
2.0
;
final
double
arrowHeadRadius
=
strokeWidth
*
1.5
;
final
double
innerRadius
=
radius
-
arrowHeadRadius
;
final
double
outerRadius
=
radius
+
arrowHeadRadius
;
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
innerRadius
=
radius
-
arrowheadRadius
;
final
double
outerRadius
=
radius
+
arrowheadRadius
;
Path
path
=
new
Path
()
..
moveTo
(
radius
+
ux
*
innerRadius
,
radius
+
uy
*
innerRadius
)
..
lineTo
(
radius
+
ux
*
outerRadius
,
radius
+
uy
*
outerRadius
)
..
lineTo
(
radius
+
ux
*
radius
+
-
uy
*
strokeWidth
*
2.0
,
radius
+
uy
*
radius
+
ux
*
strokeWidth
*
2.0
)
..
lineTo
(
arrowheadPointX
,
arrowheadPointY
)
..
close
();
Paint
paint
=
new
Paint
()
..
color
=
valueColor
...
...
@@ -420,7 +425,8 @@ class _RefreshProgressIndicatorPainter extends _CircularProgressIndicatorPainter
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
super
.
paint
(
canvas
,
size
);
paintArrowhead
(
canvas
,
size
);
if
(
arrowheadScale
>
0.0
)
paintArrowhead
(
canvas
,
size
);
}
}
...
...
@@ -472,6 +478,7 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState {
@override
Widget
_buildIndicator
(
BuildContext
context
,
double
headValue
,
double
tailValue
,
int
stepValue
,
double
rotationValue
)
{
final
double
arrowheadScale
=
config
.
value
==
null
?
0.0
:
(
config
.
value
*
2.0
).
clamp
(
0.0
,
1.0
);
return
new
Container
(
width:
_kIndicatorSize
,
height:
_kIndicatorSize
,
...
...
@@ -490,7 +497,8 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState {
tailValue:
tailValue
,
stepValue:
stepValue
,
rotationValue:
rotationValue
,
strokeWidth:
2.0
strokeWidth:
2.0
,
arrowheadScale:
arrowheadScale
)
)
)
...
...
packages/flutter/lib/src/material/refresh_indicator.dart
View file @
107cbd31
...
...
@@ -37,19 +37,24 @@ typedef Future<Null> RefreshCallback();
/// Where the refresh indicator appears: top for over-scrolls at the
/// start of the scrollable, bottom for over-scrolls at the end.
enum
RefreshIndicatorLocation
{
/// The refresh indicator
should
appear at the top of the scrollable.
/// The refresh indicator
will
appear at the top of the scrollable.
top
,
/// The refresh indicator
should
appear at the bottom of the scrollable.
/// The refresh indicator
will
appear at the bottom of the scrollable.
bottom
,
/// The refresh indicator will appear at both ends of the scrollable.
both
}
// The state machine moves through these modes only when the scrollable
// identified by scrollableKey has been scrolled to its min or max limit.
enum
_RefreshIndicatorMode
{
drag
,
armed
,
snap
,
refresh
,
di
miss
drag
,
// Pointer is down.
armed
,
// Dragged far enough that an up event will run the refresh callback.
snap
,
// Animating to the indicator's final "displacement".
refresh
,
// Running the refresh callback.
di
smiss
// Animating the indicator's fade-out.
}
/// A widget that supports the Material "swipe to refresh" idiom.
...
...
@@ -62,6 +67,11 @@ enum _RefreshIndicatorMode {
/// returns. The refresh indicator disappears after the callback's
/// Future has completed.
///
/// The required [scrollableKey] parameter identifies the scrollable widget
/// whose scrollOffset is monitored by this RefreshIndicator. The same
/// scrollableKey must also be set on the scrollable. See [Block.scrollableKey]
/// [ScrollableList.scrollableKey], etc.
///
/// See also:
///
/// * <https://www.google.com/design/spec/patterns/swipe-to-refresh.html>
...
...
@@ -75,17 +85,22 @@ class RefreshIndicator extends StatefulWidget {
this
.
scrollableKey
,
this
.
child
,
this
.
displacement
:
40.0
,
this
.
refresh
this
.
refresh
,
this
.
location
:
RefreshIndicatorLocation
.
top
})
:
super
(
key:
key
)
{
assert
(
child
!=
null
);
assert
(
refresh
!=
null
);
assert
(
location
!=
null
);
}
/// Identifies the [Scrollable] descendant of child that will cause the
/// refresh indicator to appear. Can be null if there's only one
/// [Scrollable] descendant.
/// refresh indicator to appear.
final
GlobalKey
<
ScrollableState
>
scrollableKey
;
/// The refresh indicator will be stacked on top of this child. The indicator
/// will appear when child's Scrollable descendant is over-scrolled.
final
Widget
child
;
/// The distance from the child's top or bottom edge to where the refresh indicator
/// will settle. During the drag that exposes the refresh indicator, its actual
/// displacement may significantly exceed this value.
...
...
@@ -96,9 +111,9 @@ class RefreshIndicator extends StatefulWidget {
/// Future must complete when the refresh operation is finished.
final
RefreshCallback
refresh
;
///
The refresh indicator will be stacked on top of this child. The indicator
///
will appear when child's Scrollable descendant is over-scrolled
.
final
Widget
child
;
///
Where the refresh indicator should appear, RefreshIndicatorLocation.top
///
by default
.
final
RefreshIndicatorLocation
location
;
@override
_RefreshIndicatorState
createState
()
=>
new
_RefreshIndicatorState
();
...
...
@@ -116,7 +131,7 @@ class _RefreshIndicatorState extends State<RefreshIndicator> {
double
_containerExtent
;
double
_minScrollOffset
;
double
_maxScrollOffset
;
RefreshIndicatorLocation
_location
=
RefreshIndicatorLocation
.
top
;
bool
_isIndicatorAtTop
=
true
;
_RefreshIndicatorMode
_mode
;
Future
<
Null
>
_pendingRefreshFuture
;
...
...
@@ -165,12 +180,6 @@ class _RefreshIndicatorState extends State<RefreshIndicator> {
_maxScrollOffset
=
scrollBehavior
.
maxScrollOffset
;
}
RefreshIndicatorLocation
get
_locationForScrollOffset
{
return
_scrollOffset
<
_minScrollOffset
?
RefreshIndicatorLocation
.
top
:
RefreshIndicatorLocation
.
bottom
;
}
void
_handlePointerDown
(
PointerDownEvent
event
)
{
final
ScrollableState
scrollable
=
config
.
scrollableKey
?.
currentState
;
if
(
scrollable
==
null
)
...
...
@@ -179,27 +188,70 @@ class _RefreshIndicatorState extends State<RefreshIndicator> {
_updateState
(
scrollable
);
_scaleController
.
value
=
0.0
;
_sizeController
.
value
=
0.0
;
_mode
=
_RefreshIndicatorMode
.
drag
;
setState
(()
{
_mode
=
_RefreshIndicatorMode
.
drag
;
});
}
void
_handlePointerMove
(
PointerMoveEvent
event
)
{
double
_overscrollDistance
(
)
{
final
ScrollableState
scrollable
=
config
.
scrollableKey
?.
currentState
;
if
(
scrollable
==
null
)
return
;
final
double
value
=
scrollable
.
scrollOffset
;
if
((
value
<
_minScrollOffset
||
value
>
_maxScrollOffset
)
&&
((
value
-
_scrollOffset
).
abs
()
>
kPixelScrollTolerance
.
distance
))
{
final
double
overScroll
=
value
<
_minScrollOffset
?
_minScrollOffset
-
value
:
value
-
_maxScrollOffset
;
final
double
newValue
=
overScroll
/
(
_containerExtent
*
_kDragContainerExtentPercentage
);
return
0.0
;
final
double
oldOffset
=
_scrollOffset
;
final
double
newOffset
=
scrollable
.
scrollOffset
;
_updateState
(
scrollable
);
if
((
newOffset
-
oldOffset
).
abs
()
<
kPixelScrollTolerance
.
distance
)
return
0.0
;
switch
(
config
.
location
)
{
case
RefreshIndicatorLocation
.
top
:
return
newOffset
<
_minScrollOffset
?
_minScrollOffset
-
newOffset
:
0.0
;
case
RefreshIndicatorLocation
.
bottom
:
return
newOffset
>
_maxScrollOffset
?
newOffset
-
_maxScrollOffset
:
0.0
;
case
RefreshIndicatorLocation
.
both
:
{
if
(
newOffset
<
_minScrollOffset
)
return
_minScrollOffset
-
newOffset
;
else
if
(
newOffset
>
_maxScrollOffset
)
return
newOffset
-
_maxScrollOffset
;
else
return
0.0
;
}
}
return
0.0
;
}
void
_handlePointerMove
(
PointerMoveEvent
event
)
{
final
double
overscroll
=
_overscrollDistance
();
if
(
overscroll
>
0.0
)
{
final
double
newValue
=
overscroll
/
(
_containerExtent
*
_kDragContainerExtentPercentage
);
_sizeController
.
value
=
newValue
.
clamp
(
0.0
,
1.0
);
if
(
_location
!=
_locationForScrollOffset
)
{
final
bool
newIsAtTop
=
_scrollOffset
<
_minScrollOffset
;
if
(
_isIndicatorAtTop
!=
newIsAtTop
)
{
setState
(()
{
_
location
=
_locationForScrollOffset
;
_
isIndicatorAtTop
=
newIsAtTop
;
});
}
}
// No setState() here because this doesn't cause a visual change.
_mode
=
_valueColor
.
value
.
alpha
==
0xFF
?
_RefreshIndicatorMode
.
armed
:
_RefreshIndicatorMode
.
drag
;
_updateState
(
scrollable
);
}
// Stop showing the refresh indicator
Future
<
Null
>
_dismiss
()
async
{
setState
(()
{
_mode
=
_RefreshIndicatorMode
.
dismiss
;
});
await
_scaleController
.
animateTo
(
1.0
,
duration:
_kIndicatorScaleDuration
);
if
(
mounted
&&
_mode
==
_RefreshIndicatorMode
.
dismiss
)
{
setState
(()
{
_mode
=
null
;
});
}
}
Future
<
Null
>
_doHandlePointerUp
(
PointerUpEvent
event
)
async
{
...
...
@@ -220,15 +272,11 @@ class _RefreshIndicatorState extends State<RefreshIndicator> {
bool
completed
=
_pendingRefreshFuture
!=
null
;
_pendingRefreshFuture
=
null
;
if
(
mounted
&&
completed
&&
_mode
==
_RefreshIndicatorMode
.
refresh
)
{
setState
(()
{
_mode
=
null
;
// Stop showing the indeterminate progress indicator.
});
_scaleController
.
animateTo
(
1.0
,
duration:
_kIndicatorScaleDuration
);
}
if
(
mounted
&&
completed
&&
_mode
==
_RefreshIndicatorMode
.
refresh
)
_dismiss
();
}
}
else
{
_
scaleController
.
animateTo
(
1.0
,
duration:
_kIndicatorScaleDuration
);
}
else
if
(
_mode
==
_RefreshIndicatorMode
.
drag
)
{
_
dismiss
(
);
}
}
...
...
@@ -238,7 +286,8 @@ class _RefreshIndicatorState extends State<RefreshIndicator> {
@override
Widget
build
(
BuildContext
context
)
{
final
bool
isAtTop
=
_location
==
RefreshIndicatorLocation
.
top
;
final
bool
showIndeterminateIndicator
=
_mode
==
_RefreshIndicatorMode
.
refresh
||
_mode
==
_RefreshIndicatorMode
.
dismiss
;
return
new
Listener
(
onPointerDown:
_handlePointerDown
,
onPointerMove:
_handlePointerMove
,
...
...
@@ -250,26 +299,28 @@ class _RefreshIndicatorState extends State<RefreshIndicator> {
value:
true
),
new
Positioned
(
top:
is
AtTop
?
0.0
:
null
,
bottom:
is
AtTop
?
null
:
0.0
,
top:
_isIndicator
AtTop
?
0.0
:
null
,
bottom:
_isIndicator
AtTop
?
null
:
0.0
,
left:
0.0
,
right:
0.0
,
child:
new
SizeTransition
(
axisAlignment:
is
AtTop
?
1.0
:
0.0
,
axisAlignment:
_isIndicator
AtTop
?
1.0
:
0.0
,
sizeFactor:
_sizeFactor
,
child:
new
Container
(
padding:
is
AtTop
padding:
_isIndicator
AtTop
?
new
EdgeInsets
.
only
(
top:
config
.
displacement
)
:
new
EdgeInsets
.
only
(
bottom:
config
.
displacement
),
child:
new
Align
(
alignment:
isAtTop
?
FractionalOffset
.
bottomCenter
:
FractionalOffset
.
topCenter
,
alignment:
_isIndicatorAtTop
?
FractionalOffset
.
bottomCenter
:
FractionalOffset
.
topCenter
,
child:
new
ScaleTransition
(
scale:
_scaleFactor
,
child:
new
AnimatedBuilder
(
animation:
_sizeController
,
builder:
(
BuildContext
context
,
Widget
child
)
{
return
new
RefreshProgressIndicator
(
value:
_mode
==
_RefreshIndicatorMode
.
refresh
?
null
:
_value
.
value
,
value:
showIndeterminateIndicator
?
null
:
_value
.
value
,
valueColor:
_valueColor
);
}
...
...
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