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
596637ad
Commit
596637ad
authored
Oct 03, 2016
by
Hans Muller
Committed by
GitHub
Oct 03, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added scale-to-zoom gesture support to the Gallery grid demo (#6185)
parent
57d6cc42
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
147 additions
and
9 deletions
+147
-9
grid_list_demo.dart
examples/flutter_gallery/lib/demo/grid_list_demo.dart
+110
-2
scale.dart
packages/flutter/lib/src/gestures/scale.dart
+36
-6
scale_test.dart
packages/flutter/test/gestures/scale_test.dart
+1
-1
No files found.
examples/flutter_gallery/lib/demo/grid_list_demo.dart
View file @
596637ad
...
...
@@ -11,6 +11,10 @@ enum GridDemoTileStyle {
twoLine
}
typedef
void
BannerTapCallback
(
Photo
photo
);
const
double
_kMinFlingVelocity
=
800.0
;
class
Photo
{
Photo
({
this
.
assetName
,
this
.
title
,
this
.
caption
,
this
.
isFavorite
:
false
});
...
...
@@ -24,7 +28,111 @@ class Photo {
bool
get
isValid
=>
assetName
!=
null
&&
title
!=
null
&&
caption
!=
null
&&
isFavorite
!=
null
;
}
typedef
void
BannerTapCallback
(
Photo
photo
);
class
GridPhotoViewer
extends
StatefulWidget
{
GridPhotoViewer
({
Key
key
,
this
.
photo
})
:
super
(
key:
key
);
final
Photo
photo
;
@override
_GridPhotoViewerState
createState
()
=>
new
_GridPhotoViewerState
();
}
class
_GridPhotoViewerState
extends
State
<
GridPhotoViewer
>
with
SingleTickerProviderStateMixin
{
AnimationController
_controller
;
double
_lastScale
=
1.0
;
double
_scale
=
1.0
;
Point
_lastFocalPoint
=
Point
.
origin
;
Point
_focalPoint
=
Point
.
origin
;
Animation
<
Point
>
_flingAnimation
;
@override
void
initState
()
{
super
.
initState
();
_controller
=
new
AnimationController
(
vsync:
this
)
..
addListener
(
_handleFlingAnimation
);
}
@override
void
dispose
()
{
_controller
.
dispose
();
super
.
dispose
();
}
// The minimum value for the focal point is 0,0. If the size of this
// renderer's box is w,h then the maximum value of the focal point is
// (w * _scale - w)/_scale, (h * _scale - h)/_scale.
Point
_clampFocalPoint
(
Point
point
)
{
final
RenderBox
box
=
context
.
findRenderObject
();
final
double
inverseScale
=
(
_scale
-
1.0
)
/
_scale
;
final
Point
bottomRight
=
new
Point
(
box
.
size
.
width
*
inverseScale
,
box
.
size
.
height
*
inverseScale
);
return
new
Point
(
point
.
x
.
clamp
(
0.0
,
bottomRight
.
x
),
point
.
y
.
clamp
(
0.0
,
bottomRight
.
y
));
}
void
_handleFlingAnimation
()
{
setState
(()
{
_focalPoint
=
_flingAnimation
.
value
;
_lastFocalPoint
=
_focalPoint
;
});
}
void
_handleOnScaleStart
(
Point
focalPoint
)
{
setState
(()
{
_lastScale
=
1.0
;
_lastFocalPoint
=
focalPoint
;
// The fling animation stops if an input gesture starts.
_controller
.
stop
();
});
}
void
_handleOnScaleUpdate
(
double
scale
,
Point
focalPoint
)
{
setState
(()
{
_scale
=
(
_scale
+
(
scale
-
_lastScale
)).
clamp
(
1.0
,
3.0
);
_lastScale
=
scale
;
_focalPoint
=
_clampFocalPoint
(
_focalPoint
+
(
_lastFocalPoint
-
focalPoint
));
_lastFocalPoint
=
focalPoint
;
});
}
void
_handleOnScaleEnd
(
Velocity
flingVelocity
)
{
final
double
magnitude
=
flingVelocity
.
pixelsPerSecond
.
distance
;
if
(
magnitude
<
_kMinFlingVelocity
)
return
;
final
Offset
direction
=
flingVelocity
.
pixelsPerSecond
/
magnitude
;
final
RenderBox
box
=
context
.
findRenderObject
();
final
double
distance
=
(
Point
.
origin
&
box
.
size
).
shortestSide
;
_flingAnimation
=
new
Tween
<
Point
>(
begin:
_focalPoint
,
end:
_clampFocalPoint
(
_focalPoint
+
direction
*
-
distance
)
).
animate
(
_controller
);
_controller
..
value
=
0.0
..
fling
(
velocity:
magnitude
/
1000.0
);
}
@override
Widget
build
(
BuildContext
context
)
{
return
new
LayoutBuilder
(
builder:
(
BuildContext
context
,
BoxConstraints
constraints
)
{
return
new
GestureDetector
(
onScaleStart:
_handleOnScaleStart
,
onScaleUpdate:
_handleOnScaleUpdate
,
onScaleEnd:
_handleOnScaleEnd
,
child:
new
Transform
(
transform:
new
Matrix4
.
identity
()
..
translate
(
_focalPoint
.
x
*
(
1.0
-
_scale
),
_focalPoint
.
y
*
(
1.0
-
_scale
))
..
scale
(
_scale
),
child:
new
ClipRect
(
child:
new
Image
.
asset
(
config
.
photo
.
assetName
,
fit:
ImageFit
.
cover
)
)
)
);
}
);
}
}
class
GridDemoPhotoItem
extends
StatelessWidget
{
GridDemoPhotoItem
({
...
...
@@ -51,7 +159,7 @@ class GridDemoPhotoItem extends StatelessWidget {
),
body:
new
Hero
(
tag:
photo
.
tag
,
child:
new
Image
.
asset
(
photo
.
assetName
,
fit:
ImageFit
.
cover
)
child:
new
GridPhotoViewer
(
photo:
photo
),
)
);
}
...
...
packages/flutter/lib/src/gestures/scale.dart
View file @
596637ad
...
...
@@ -6,6 +6,7 @@ import 'arena.dart';
import
'recognizer.dart'
;
import
'constants.dart'
;
import
'events.dart'
;
import
'velocity_tracker.dart'
;
/// The possible states of a [ScaleGestureRecognizer].
enum
ScaleState
{
...
...
@@ -35,7 +36,13 @@ typedef void GestureScaleStartCallback(Point focalPoint);
typedef
void
GestureScaleUpdateCallback
(
double
scale
,
Point
focalPoint
);
/// Signature for when the pointers are no longer in contact with the screen.
typedef
void
GestureScaleEndCallback
(
);
typedef
void
GestureScaleEndCallback
(
Velocity
flingVelocity
);
bool
_isFlingGesture
(
Velocity
velocity
)
{
assert
(
velocity
!=
null
);
final
double
speedSquared
=
velocity
.
pixelsPerSecond
.
distanceSquared
;
return
speedSquared
>
kMinFlingVelocity
*
kMinFlingVelocity
;
}
/// Recognizes a scale gesture.
///
...
...
@@ -61,12 +68,14 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
double
_initialSpan
;
double
_currentSpan
;
Map
<
int
,
Point
>
_pointerLocations
;
Map
<
int
,
VelocityTracker
>
_velocityTrackers
=
new
Map
<
int
,
VelocityTracker
>();
double
get
_scaleFactor
=>
_initialSpan
>
0.0
?
_currentSpan
/
_initialSpan
:
1.0
;
@override
void
addPointer
(
PointerEvent
event
)
{
startTrackingPointer
(
event
.
pointer
);
_velocityTrackers
[
event
.
pointer
]
=
new
VelocityTracker
();
if
(
_state
==
ScaleState
.
ready
)
{
_state
=
ScaleState
.
possible
;
_initialSpan
=
0.0
;
...
...
@@ -80,6 +89,9 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
assert
(
_state
!=
ScaleState
.
ready
);
bool
configChanged
=
false
;
if
(
event
is
PointerMoveEvent
)
{
VelocityTracker
tracker
=
_velocityTrackers
[
event
.
pointer
];
assert
(
tracker
!=
null
);
tracker
.
addPosition
(
event
.
timeStamp
,
event
.
position
);
_pointerLocations
[
event
.
pointer
]
=
event
.
position
;
}
else
if
(
event
is
PointerDownEvent
)
{
configChanged
=
true
;
...
...
@@ -89,12 +101,12 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
_pointerLocations
.
remove
(
event
.
pointer
);
}
_update
(
configChanged
);
_update
(
configChanged
,
event
.
pointer
);
stopTrackingIfPointerNoLongerDown
(
event
);
}
void
_update
(
bool
configChanged
)
{
void
_update
(
bool
configChanged
,
int
pointer
)
{
int
count
=
_pointerLocations
.
keys
.
length
;
// Compute the focal point
...
...
@@ -112,8 +124,20 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
if
(
configChanged
)
{
_initialSpan
=
_currentSpan
;
if
(
_state
==
ScaleState
.
started
)
{
if
(
onEnd
!=
null
)
onEnd
();
if
(
onEnd
!=
null
)
{
VelocityTracker
tracker
=
_velocityTrackers
[
pointer
];
assert
(
tracker
!=
null
);
Velocity
velocity
=
tracker
.
getVelocity
();
if
(
velocity
!=
null
&&
_isFlingGesture
(
velocity
))
{
final
Offset
pixelsPerSecond
=
velocity
.
pixelsPerSecond
;
if
(
pixelsPerSecond
.
distanceSquared
>
kMaxFlingVelocity
*
kMaxFlingVelocity
)
velocity
=
new
Velocity
(
pixelsPerSecond:
(
pixelsPerSecond
/
pixelsPerSecond
.
distance
)
*
kMaxFlingVelocity
);
onEnd
(
velocity
);
}
else
{
onEnd
(
Velocity
.
zero
);
}
}
_state
=
ScaleState
.
accepted
;
}
}
...
...
@@ -140,7 +164,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
void
acceptGesture
(
int
pointer
)
{
if
(
_state
!=
ScaleState
.
accepted
)
{
_state
=
ScaleState
.
accepted
;
_update
(
false
);
_update
(
false
,
pointer
);
}
}
...
...
@@ -162,6 +186,12 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
_state
=
ScaleState
.
ready
;
}
@override
void
dispose
()
{
_velocityTrackers
.
clear
();
super
.
dispose
();
}
@override
String
toStringShort
()
=>
'scale'
;
}
packages/flutter/test/gestures/scale_test.dart
View file @
596637ad
...
...
@@ -28,7 +28,7 @@ void main() {
};
bool
didEndScale
=
false
;
scale
.
onEnd
=
()
{
scale
.
onEnd
=
(
Velocity
flingVelocity
)
{
didEndScale
=
true
;
};
...
...
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