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
4f672dc0
Commit
4f672dc0
authored
Dec 24, 2015
by
Ian Hickson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1020 from Hixie/transform
RenderFractionalTranslation and Dismissable
parents
a9ddbb4e
9bad312a
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
234 additions
and
104 deletions
+234
-104
box_painter.dart
packages/flutter/lib/src/painting/box_painter.dart
+34
-15
image.dart
packages/flutter/lib/src/rendering/image.dart
+2
-2
proxy_box.dart
packages/flutter/lib/src/rendering/proxy_box.dart
+85
-13
shifted_box.dart
packages/flutter/lib/src/rendering/shifted_box.dart
+3
-4
stack.dart
packages/flutter/lib/src/rendering/stack.dart
+1
-3
basic.dart
packages/flutter/lib/src/widgets/basic.dart
+34
-3
dismissable.dart
packages/flutter/lib/src/widgets/dismissable.dart
+39
-40
transitions.dart
packages/flutter/lib/src/widgets/transitions.dart
+4
-4
dismissable_test.dart
packages/flutter/test/widget/dismissable_test.dart
+32
-20
No files found.
packages/flutter/lib/src/painting/box_painter.dart
View file @
4f672dc0
...
...
@@ -510,36 +510,55 @@ void paintImage({
/// FractionalOffset(1.0, 0.0) represents the top right of the Size,
/// FractionalOffset(0.0, 1.0) represents the bottom left of the Size,
class
FractionalOffset
{
const
FractionalOffset
(
this
.
x
,
this
.
y
);
final
double
x
;
final
double
y
;
const
FractionalOffset
(
this
.
dx
,
this
.
dy
);
final
double
dx
;
final
double
dy
;
static
const
FractionalOffset
zero
=
const
FractionalOffset
(
0.0
,
0.0
);
FractionalOffset
operator
-()
{
return
new
FractionalOffset
(-
dx
,
-
dy
);
}
FractionalOffset
operator
-(
FractionalOffset
other
)
{
return
new
FractionalOffset
(
x
-
other
.
x
,
y
-
other
.
y
);
return
new
FractionalOffset
(
dx
-
other
.
dx
,
dy
-
other
.
d
y
);
}
FractionalOffset
operator
+(
FractionalOffset
other
)
{
return
new
FractionalOffset
(
x
+
other
.
x
,
y
+
other
.
y
);
return
new
FractionalOffset
(
dx
+
other
.
dx
,
dy
+
other
.
d
y
);
}
FractionalOffset
operator
*(
double
other
)
{
return
new
FractionalOffset
(
x
*
other
,
y
*
other
);
return
new
FractionalOffset
(
dx
*
other
,
dy
*
other
);
}
FractionalOffset
operator
/(
double
other
)
{
return
new
FractionalOffset
(
dx
/
other
,
dy
/
other
);
}
FractionalOffset
operator
~/(
double
other
)
{
return
new
FractionalOffset
((
dx
~/
other
).
toDouble
(),
(
dy
~/
other
).
toDouble
());
}
FractionalOffset
operator
%(
double
other
)
{
return
new
FractionalOffset
(
dx
%
other
,
dy
%
other
);
}
Offset
alongOffset
(
Offset
other
)
{
return
new
Offset
(
dx
*
other
.
dx
,
dy
*
other
.
dy
);
}
Offset
alongSize
(
Size
other
)
{
return
new
Offset
(
dx
*
other
.
width
,
dy
*
other
.
height
);
}
bool
operator
==(
dynamic
other
)
{
if
(
other
is
!
FractionalOffset
)
return
false
;
final
FractionalOffset
typedOther
=
other
;
return
x
==
typedOther
.
x
&&
y
==
typedOther
.
y
;
return
dx
==
typedOther
.
d
x
&&
dy
==
typedOther
.
d
y
;
}
int
get
hashCode
=>
hashValues
(
x
,
y
);
int
get
hashCode
=>
hashValues
(
dx
,
d
y
);
static
FractionalOffset
lerp
(
FractionalOffset
a
,
FractionalOffset
b
,
double
t
)
{
if
(
a
==
null
&&
b
==
null
)
return
null
;
if
(
a
==
null
)
return
new
FractionalOffset
(
b
.
x
*
t
,
b
.
y
*
t
);
return
new
FractionalOffset
(
b
.
dx
*
t
,
b
.
d
y
*
t
);
if
(
b
==
null
)
return
new
FractionalOffset
(
b
.
x
*
(
1.0
-
t
),
b
.
y
*
(
1.0
-
t
));
return
new
FractionalOffset
(
ui
.
lerpDouble
(
a
.
x
,
b
.
x
,
t
),
ui
.
lerpDouble
(
a
.
y
,
b
.
y
,
t
));
return
new
FractionalOffset
(
b
.
dx
*
(
1.0
-
t
),
b
.
d
y
*
(
1.0
-
t
));
return
new
FractionalOffset
(
ui
.
lerpDouble
(
a
.
dx
,
b
.
dx
,
t
),
ui
.
lerpDouble
(
a
.
dy
,
b
.
d
y
,
t
));
}
String
toString
()
=>
'
$runtimeType
(
$
x
,
$
y
)'
;
String
toString
()
=>
'
$runtimeType
(
$
dx
,
$d
y
)'
;
}
/// A background image for a box.
...
...
@@ -919,8 +938,8 @@ class _BoxDecorationPainter extends BoxPainter {
rect:
rect
,
image:
image
,
colorFilter:
backgroundImage
.
colorFilter
,
alignX:
backgroundImage
.
alignment
?.
x
,
alignY:
backgroundImage
.
alignment
?.
y
,
alignX:
backgroundImage
.
alignment
?.
d
x
,
alignY:
backgroundImage
.
alignment
?.
d
y
,
fit:
backgroundImage
.
fit
,
repeat:
backgroundImage
.
repeat
);
...
...
packages/flutter/lib/src/rendering/image.dart
View file @
4f672dc0
...
...
@@ -216,8 +216,8 @@ class RenderImage extends RenderBox {
image:
_image
,
colorFilter:
_colorFilter
,
fit:
_fit
,
alignX:
_alignment
?.
x
,
alignY:
_alignment
?.
y
,
alignX:
_alignment
?.
d
x
,
alignY:
_alignment
?.
d
y
,
centerSlice:
_centerSlice
,
repeat:
_repeat
);
...
...
packages/flutter/lib/src/rendering/proxy_box.dart
View file @
4f672dc0
...
...
@@ -851,10 +851,11 @@ class RenderTransform extends RenderProxyBox {
Matrix4
transform
,
Offset
origin
,
FractionalOffset
alignment
,
this
.
transformHitTests
:
true
,
RenderBox
child
})
:
super
(
child
)
{
assert
(
transform
!=
null
);
assert
(
alignment
==
null
||
(
alignment
.
x
!=
null
&&
alignment
.
y
!=
null
));
assert
(
alignment
==
null
||
(
alignment
.
dx
!=
null
&&
alignment
.
d
y
!=
null
));
this
.
transform
=
transform
;
this
.
alignment
=
alignment
;
this
.
origin
=
origin
;
...
...
@@ -881,13 +882,21 @@ class RenderTransform extends RenderProxyBox {
FractionalOffset
get
alignment
=>
_alignment
;
FractionalOffset
_alignment
;
void
set
alignment
(
FractionalOffset
newAlignment
)
{
assert
(
newAlignment
==
null
||
(
newAlignment
.
x
!=
null
&&
newAlignment
.
y
!=
null
));
assert
(
newAlignment
==
null
||
(
newAlignment
.
dx
!=
null
&&
newAlignment
.
d
y
!=
null
));
if
(
_alignment
==
newAlignment
)
return
;
_alignment
=
newAlignment
;
markNeedsPaint
();
}
/// When set to true, hit tests are performed based on the position of the
/// child as it is painted. When set to false, hit tests are performed
/// ignoring the transformation.
///
/// applyPaintTransform(), and therefore localToGlobal() and globalToLocal(),
/// always honor the transformation, regardless of the value of this property.
bool
transformHitTests
;
// Note the lack of a getter for transform because Matrix4 is not immutable
Matrix4
_transform
;
...
...
@@ -942,25 +951,29 @@ class RenderTransform extends RenderProxyBox {
Matrix4
result
=
new
Matrix4
.
identity
();
if
(
_origin
!=
null
)
result
.
translate
(
_origin
.
dx
,
_origin
.
dy
);
if
(
_alignment
!=
null
)
result
.
translate
(
_alignment
.
x
*
size
.
width
,
_alignment
.
y
*
size
.
height
);
Offset
translation
;
if
(
_alignment
!=
null
)
{
translation
=
_alignment
.
alongSize
(
size
);
result
.
translate
(
translation
.
dx
,
translation
.
dy
);
}
result
.
multiply
(
_transform
);
if
(
_alignment
!=
null
)
result
.
translate
(-
_alignment
.
x
*
size
.
width
,
-
_alignment
.
y
*
size
.
height
);
result
.
translate
(-
translation
.
dx
,
-
translation
.
dy
);
if
(
_origin
!=
null
)
result
.
translate
(-
_origin
.
dx
,
-
_origin
.
dy
);
return
result
;
}
bool
hitTest
(
HitTestResult
result
,
{
Point
position
})
{
Matrix4
inverse
=
new
Matrix4
.
zero
();
// TODO(abarth): Check the determinant for degeneracy.
inverse
.
copyInverse
(
_effectiveTransform
);
Vector3
position3
=
new
Vector3
(
position
.
x
,
position
.
y
,
0.0
);
Vector3
transformed3
=
inverse
.
transform3
(
position3
);
Point
transformed
=
new
Point
(
transformed3
.
x
,
transformed3
.
y
);
return
super
.
hitTest
(
result
,
position:
transformed
);
if
(
transformHitTests
)
{
Matrix4
inverse
=
new
Matrix4
.
zero
();
// TODO(abarth): Check the determinant for degeneracy.
inverse
.
copyInverse
(
_effectiveTransform
);
Vector3
position3
=
new
Vector3
(
position
.
x
,
position
.
y
,
0.0
);
Vector3
transformed3
=
inverse
.
transform3
(
position3
);
position
=
new
Point
(
transformed3
.
x
,
transformed3
.
y
);
}
return
super
.
hitTest
(
result
,
position:
position
);
}
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
...
...
@@ -985,6 +998,65 @@ class RenderTransform extends RenderProxyBox {
settings
.
addAll
(
debugDescribeTransform
(
_transform
));
settings
.
add
(
'origin:
$origin
'
);
settings
.
add
(
'alignment:
$alignment
'
);
settings
.
add
(
'transformHitTests:
$transformHitTests
'
);
}
}
/// Applies a translation transformation before painting its child. The
/// translation is expressed as a [FractionalOffset] relative to the
/// RenderFractionalTranslation box's size. Hit tests will only be detected
/// inside the bounds of the RenderFractionalTranslation, even if the contents
/// are offset such that they overflow.
class
RenderFractionalTranslation
extends
RenderProxyBox
{
RenderFractionalTranslation
({
FractionalOffset
translation
,
this
.
transformHitTests
:
true
,
RenderBox
child
})
:
_translation
=
translation
,
super
(
child
)
{
assert
(
translation
==
null
||
(
translation
.
dx
!=
null
&&
translation
.
dy
!=
null
));
}
/// The translation to apply to the child, as a multiple of the size.
FractionalOffset
get
translation
=>
_translation
;
FractionalOffset
_translation
;
void
set
translation
(
FractionalOffset
newTranslation
)
{
assert
(
newTranslation
==
null
||
(
newTranslation
.
dx
!=
null
&&
newTranslation
.
dy
!=
null
));
if
(
_translation
==
newTranslation
)
return
;
_translation
=
newTranslation
;
markNeedsPaint
();
}
/// When set to true, hit tests are performed based on the position of the
/// child as it is painted. When set to false, hit tests are performed
/// ignoring the transformation.
///
/// applyPaintTransform(), and therefore localToGlobal() and globalToLocal(),
/// always honor the transformation, regardless of the value of this property.
bool
transformHitTests
;
bool
hitTest
(
HitTestResult
result
,
{
Point
position
})
{
assert
(!
needsLayout
);
if
(
transformHitTests
)
position
=
new
Point
(
position
.
x
-
translation
.
dx
*
size
.
width
,
position
.
y
-
translation
.
dy
*
size
.
height
);
return
super
.
hitTest
(
result
,
position:
position
);
}
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
assert
(!
needsLayout
);
if
(
child
!=
null
)
super
.
paint
(
context
,
offset
+
translation
.
alongSize
(
size
));
}
void
applyPaintTransform
(
RenderBox
child
,
Matrix4
transform
)
{
transform
.
translate
(
translation
.
dx
*
size
.
width
,
translation
.
dy
*
size
.
height
);
super
.
applyPaintTransform
(
child
,
transform
);
}
void
debugDescribeSettings
(
List
<
String
>
settings
)
{
super
.
debugDescribeSettings
(
settings
);
settings
.
add
(
'translation:
$translation
'
);
settings
.
add
(
'transformHitTests:
$transformHitTests
'
);
}
}
...
...
packages/flutter/lib/src/rendering/shifted_box.dart
View file @
4f672dc0
...
...
@@ -179,7 +179,7 @@ class RenderPositionedBox extends RenderShiftedBox {
_widthFactor
=
widthFactor
,
_heightFactor
=
heightFactor
,
super
(
child
)
{
assert
(
alignment
!=
null
&&
alignment
.
x
!=
null
&&
alignment
.
y
!=
null
);
assert
(
alignment
!=
null
&&
alignment
.
dx
!=
null
&&
alignment
.
d
y
!=
null
);
assert
(
widthFactor
==
null
||
widthFactor
>=
0.0
);
assert
(
heightFactor
==
null
||
heightFactor
>=
0.0
);
}
...
...
@@ -196,7 +196,7 @@ class RenderPositionedBox extends RenderShiftedBox {
FractionalOffset
get
alignment
=>
_alignment
;
FractionalOffset
_alignment
;
void
set
alignment
(
FractionalOffset
newAlignment
)
{
assert
(
newAlignment
!=
null
&&
newAlignment
.
x
!=
null
&&
newAlignment
.
y
!=
null
);
assert
(
newAlignment
!=
null
&&
newAlignment
.
dx
!=
null
&&
newAlignment
.
d
y
!=
null
);
if
(
_alignment
==
newAlignment
)
return
;
_alignment
=
newAlignment
;
...
...
@@ -237,9 +237,8 @@ class RenderPositionedBox extends RenderShiftedBox {
child
.
layout
(
constraints
.
loosen
(),
parentUsesSize:
true
);
size
=
constraints
.
constrain
(
new
Size
(
shrinkWrapWidth
?
child
.
size
.
width
*
(
_widthFactor
??
1.0
)
:
double
.
INFINITY
,
shrinkWrapHeight
?
child
.
size
.
height
*
(
_heightFactor
??
1.0
)
:
double
.
INFINITY
));
final
Offset
delta
=
size
-
child
.
size
;
final
BoxParentData
childParentData
=
child
.
parentData
;
childParentData
.
position
=
delta
.
scale
(
_alignment
.
x
,
_alignment
.
y
).
toPoint
();
childParentData
.
position
=
_alignment
.
alongOffset
(
size
-
child
.
size
).
toPoint
();
}
else
{
size
=
constraints
.
constrain
(
new
Size
(
shrinkWrapWidth
?
0.0
:
double
.
INFINITY
,
shrinkWrapHeight
?
0.0
:
double
.
INFINITY
));
...
...
packages/flutter/lib/src/rendering/stack.dart
View file @
4f672dc0
...
...
@@ -328,9 +328,7 @@ abstract class RenderStackBase extends RenderBox
final
StackParentData
childParentData
=
child
.
parentData
;
if
(!
childParentData
.
isPositioned
)
{
double
x
=
(
size
.
width
-
child
.
size
.
width
)
*
alignment
.
x
;
double
y
=
(
size
.
height
-
child
.
size
.
height
)
*
alignment
.
y
;
childParentData
.
position
=
new
Point
(
x
,
y
);
childParentData
.
position
=
alignment
.
alongOffset
(
size
-
child
.
size
).
toPoint
();
}
else
{
BoxConstraints
childConstraints
=
const
BoxConstraints
();
...
...
packages/flutter/lib/src/widgets/basic.dart
View file @
4f672dc0
...
...
@@ -270,7 +270,7 @@ class ClipOval extends OneChildRenderObjectWidget {
/// Applies a transformation before painting its child.
class
Transform
extends
OneChildRenderObjectWidget
{
Transform
({
Key
key
,
this
.
transform
,
this
.
origin
,
this
.
alignment
,
Widget
child
})
Transform
({
Key
key
,
this
.
transform
,
this
.
origin
,
this
.
alignment
,
this
.
transformHitTests
:
true
,
Widget
child
})
:
super
(
key:
key
,
child:
child
)
{
assert
(
transform
!=
null
);
}
...
...
@@ -291,12 +291,43 @@ class Transform extends OneChildRenderObjectWidget {
/// If it is specificed at the same time as an offset, both are applied.
final
FractionalOffset
alignment
;
RenderTransform
createRenderObject
()
=>
new
RenderTransform
(
transform:
transform
,
origin:
origin
,
alignment:
alignment
);
/// Whether to apply the translation when performing hit tests.
final
bool
transformHitTests
;
RenderTransform
createRenderObject
()
=>
new
RenderTransform
(
transform:
transform
,
origin:
origin
,
alignment:
alignment
,
transformHitTests:
transformHitTests
);
void
updateRenderObject
(
RenderTransform
renderObject
,
Transform
oldWidget
)
{
renderObject
.
transform
=
transform
;
renderObject
.
origin
=
origin
;
renderObject
.
alignment
=
alignment
;
renderObject
.
transformHitTests
=
transformHitTests
;
}
}
/// Applies a translation expressed as a fraction of the box's size before
/// painting its child.
class
FractionalTranslation
extends
OneChildRenderObjectWidget
{
FractionalTranslation
({
Key
key
,
this
.
translation
,
this
.
transformHitTests
:
true
,
Widget
child
})
:
super
(
key:
key
,
child:
child
)
{
assert
(
translation
!=
null
);
}
/// The offset by which to translate the child, as a multiple of its size.
final
FractionalOffset
translation
;
/// Whether to apply the translation when performing hit tests.
final
bool
transformHitTests
;
RenderFractionalTranslation
createRenderObject
()
=>
new
RenderFractionalTranslation
(
translation:
translation
,
transformHitTests:
transformHitTests
);
void
updateRenderObject
(
RenderFractionalTranslation
renderObject
,
FractionalTranslation
oldWidget
)
{
renderObject
.
translation
=
translation
;
renderObject
.
transformHitTests
=
transformHitTests
;
}
}
...
...
@@ -335,7 +366,7 @@ class Align extends OneChildRenderObjectWidget {
this
.
heightFactor
,
Widget
child
})
:
super
(
key:
key
,
child:
child
)
{
assert
(
alignment
!=
null
&&
alignment
.
x
!=
null
&&
alignment
.
y
!=
null
);
assert
(
alignment
!=
null
&&
alignment
.
dx
!=
null
&&
alignment
.
d
y
!=
null
);
assert
(
widthFactor
==
null
||
widthFactor
>=
0.0
);
assert
(
heightFactor
==
null
||
heightFactor
>=
0.0
);
}
...
...
packages/flutter/lib/src/widgets/dismissable.dart
View file @
4f672dc0
...
...
@@ -11,9 +11,9 @@ import 'transitions.dart';
import
'framework.dart'
;
import
'gesture_detector.dart'
;
const
Duration
_kCardDismiss
Fadeout
=
const
Duration
(
milliseconds:
200
);
const
Duration
_kCard
DismissResize
=
const
Duration
(
milliseconds:
300
);
const
Curve
_kCard
DismissResiz
eCurve
=
const
Interval
(
0.4
,
1.0
,
curve:
Curves
.
ease
);
const
Duration
_kCardDismiss
Duration
=
const
Duration
(
milliseconds:
200
);
const
Duration
_kCard
ResizeDuration
=
const
Duration
(
milliseconds:
300
);
const
Curve
_kCard
ResizeTim
eCurve
=
const
Interval
(
0.4
,
1.0
,
curve:
Curves
.
ease
);
const
double
_kMinFlingVelocity
=
700.0
;
const
double
_kMinFlingVelocityDelta
=
400.0
;
const
double
_kFlingVelocityScale
=
1.0
/
300.0
;
...
...
@@ -60,7 +60,7 @@ class Dismissable extends StatefulComponent {
/// Called when the widget changes size (i.e., when contracting after being dismissed).
final
VoidCallback
onResized
;
/// Called when the widget has been dismissed.
/// Called when the widget has been dismissed
, after finishing resizing
.
final
VoidCallback
onDismissed
;
/// The direction in which the widget can be dismissed.
...
...
@@ -72,14 +72,14 @@ class Dismissable extends StatefulComponent {
class
_DismissableState
extends
State
<
Dismissable
>
{
void
initState
()
{
super
.
initState
();
_
fadePerformance
=
new
Performance
(
duration:
_kCardDismissFadeout
);
_
fade
Performance
.
addStatusListener
((
PerformanceStatus
status
)
{
_
dismissPerformance
=
new
Performance
(
duration:
_kCardDismissDuration
);
_
dismiss
Performance
.
addStatusListener
((
PerformanceStatus
status
)
{
if
(
status
==
PerformanceStatus
.
completed
)
_handle
Fade
Completed
();
_handle
Dismiss
Completed
();
});
}
Performance
_
fade
Performance
;
Performance
_
dismiss
Performance
;
Performance
_resizePerformance
;
Size
_size
;
...
...
@@ -87,7 +87,7 @@ class _DismissableState extends State<Dismissable> {
bool
_dragUnderway
=
false
;
void
dispose
()
{
_
fade
Performance
?.
stop
();
_
dismiss
Performance
?.
stop
();
_resizePerformance
?.
stop
();
super
.
dispose
();
}
...
...
@@ -99,13 +99,13 @@ class _DismissableState extends State<Dismissable> {
config
.
direction
==
DismissDirection
.
down
;
}
void
_handle
Fade
Completed
()
{
void
_handle
Dismiss
Completed
()
{
if
(!
_dragUnderway
)
_startResizePerformance
();
}
bool
get
_isActive
{
return
_size
!=
null
&&
(
_dragUnderway
||
_
fade
Performance
.
isAnimating
);
return
_size
!=
null
&&
(
_dragUnderway
||
_
dismiss
Performance
.
isAnimating
);
}
void
_maybeCallOnResized
()
{
...
...
@@ -120,13 +120,12 @@ class _DismissableState extends State<Dismissable> {
void
_startResizePerformance
()
{
assert
(
_size
!=
null
);
assert
(
_
fade
Performance
!=
null
);
assert
(
_
fade
Performance
.
isCompleted
);
assert
(
_
dismiss
Performance
!=
null
);
assert
(
_
dismiss
Performance
.
isCompleted
);
assert
(
_resizePerformance
==
null
);
setState
(()
{
_resizePerformance
=
new
Performance
()
..
duration
=
_kCard
DismissResize
..
duration
=
_kCard
ResizeDuration
..
addListener
(
_handleResizeProgressChanged
);
_resizePerformance
.
play
();
});
...
...
@@ -140,21 +139,21 @@ class _DismissableState extends State<Dismissable> {
}
void
_handleDragStart
(
_
)
{
if
(
_
fade
Performance
.
isAnimating
)
if
(
_
dismiss
Performance
.
isAnimating
)
return
;
setState
(()
{
_dragUnderway
=
true
;
_dragExtent
=
0.0
;
_
fade
Performance
.
progress
=
0.0
;
_
dismiss
Performance
.
progress
=
0.0
;
});
}
void
_handleDragUpdate
(
double
delta
)
{
if
(!
_isActive
||
_
fade
Performance
.
isAnimating
)
if
(!
_isActive
||
_
dismiss
Performance
.
isAnimating
)
return
;
double
oldDragExtent
=
_dragExtent
;
switch
(
config
.
direction
)
{
switch
(
config
.
direction
)
{
case
DismissDirection
.
horizontal
:
case
DismissDirection
.
vertical
:
_dragExtent
+=
delta
;
...
...
@@ -181,8 +180,8 @@ class _DismissableState extends State<Dismissable> {
// the performances.
});
}
if
(!
_
fade
Performance
.
isAnimating
)
_
fadePerformance
.
progress
=
_dragExtent
.
abs
()
/
(
_size
.
width
*
_kDismissCardThreshold
)
;
if
(!
_
dismiss
Performance
.
isAnimating
)
_
dismissPerformance
.
progress
=
_dragExtent
.
abs
()
/
_size
.
width
;
}
bool
_isFlingGesture
(
ui
.
Offset
velocity
)
{
...
...
@@ -215,19 +214,20 @@ class _DismissableState extends State<Dismissable> {
}
void
_handleDragEnd
(
ui
.
Offset
velocity
)
{
if
(!
_isActive
||
_
fade
Performance
.
isAnimating
)
if
(!
_isActive
||
_
dismiss
Performance
.
isAnimating
)
return
;
setState
(()
{
_dragUnderway
=
false
;
if
(
_
fade
Performance
.
isCompleted
)
{
if
(
_
dismiss
Performance
.
isCompleted
)
{
_startResizePerformance
();
}
else
if
(
_isFlingGesture
(
velocity
))
{
double
flingVelocity
=
_directionIsYAxis
?
velocity
.
dy
:
velocity
.
dx
;
_dragExtent
=
flingVelocity
.
sign
;
_fadePerformance
.
fling
(
velocity:
flingVelocity
.
abs
()
*
_kFlingVelocityScale
);
_dismissPerformance
.
fling
(
velocity:
flingVelocity
.
abs
()
*
_kFlingVelocityScale
);
}
else
if
(
_dismissPerformance
.
progress
>
_kDismissCardThreshold
)
{
_dismissPerformance
.
forward
();
}
else
{
_
fade
Performance
.
reverse
();
_
dismiss
Performance
.
reverse
();
}
});
}
...
...
@@ -238,12 +238,12 @@ class _DismissableState extends State<Dismissable> {
});
}
Poin
t
get
_activeCardDragEndPoint
{
FractionalOffse
t
get
_activeCardDragEndPoint
{
if
(!
_isActive
)
return
Point
.
origin
;
assert
(
_size
!=
null
);
double
extent
=
_directionIsYAxis
?
_size
.
height
:
_size
.
width
;
return
new
Point
(
_dragExtent
.
sign
*
extent
*
_kDismissCardThreshold
,
0.0
);
return
FractionalOffset
.
zero
;
if
(
_directionIsYAxis
)
return
new
FractionalOffset
(
0.0
,
_dragExtent
.
sign
)
;
return
new
FractionalOffset
(
_dragExtent
.
sign
,
0.0
);
}
Widget
build
(
BuildContext
context
)
{
...
...
@@ -254,7 +254,7 @@ class _DismissableState extends State<Dismissable> {
AnimatedValue
<
double
>
squashAxisExtent
=
new
AnimatedValue
<
double
>(
_directionIsYAxis
?
_size
.
width
:
_size
.
height
,
end:
0.0
,
curve:
_kCard
DismissResiz
eCurve
curve:
_kCard
ResizeTim
eCurve
);
return
new
SquashTransition
(
...
...
@@ -274,14 +274,13 @@ class _DismissableState extends State<Dismissable> {
behavior:
HitTestBehavior
.
opaque
,
child:
new
SizeObserver
(
onSizeChanged:
_handleSizeChanged
,
child:
new
FadeTransition
(
performance:
_fadePerformance
.
view
,
opacity:
new
AnimatedValue
<
double
>(
1.0
,
end:
0.0
),
child:
new
SlideTransition
(
performance:
_fadePerformance
.
view
,
position:
new
AnimatedValue
<
Point
>(
Point
.
origin
,
end:
_activeCardDragEndPoint
),
child:
config
.
child
)
child:
new
SlideTransition
(
performance:
_dismissPerformance
.
view
,
position:
new
AnimatedValue
<
FractionalOffset
>(
FractionalOffset
.
zero
,
end:
_activeCardDragEndPoint
),
child:
config
.
child
)
)
);
...
...
packages/flutter/lib/src/widgets/transitions.dart
View file @
4f672dc0
...
...
@@ -82,18 +82,18 @@ class SlideTransition extends TransitionWithChild {
Key
key
,
this
.
position
,
PerformanceView
performance
,
this
.
transformHitTests
:
true
,
Widget
child
})
:
super
(
key:
key
,
performance:
performance
,
child:
child
);
final
AnimatedValue
<
Point
>
position
;
final
AnimatedValue
<
FractionalOffset
>
position
;
bool
transformHitTests
;
Widget
buildWithChild
(
BuildContext
context
,
Widget
child
)
{
performance
.
updateVariable
(
position
);
Matrix4
transform
=
new
Matrix4
.
identity
()
..
translate
(
position
.
value
.
x
,
position
.
value
.
y
);
return
new
Transform
(
transform:
transform
,
child:
child
);
return
new
FractionalTranslation
(
translation:
position
.
value
,
transformHitTests:
transformHitTests
,
child:
child
);
}
}
...
...
packages/flutter/test/widget/dismissable_test.dart
View file @
4f672dc0
...
...
@@ -12,11 +12,11 @@ ScrollDirection scrollDirection = ScrollDirection.vertical;
DismissDirection
dismissDirection
=
DismissDirection
.
horizontal
;
List
<
int
>
dismissedItems
=
<
int
>[];
void
handleOnResized
(
item
)
{
void
handleOnResized
(
i
nt
i
tem
)
{
expect
(
dismissedItems
.
contains
(
item
),
isFalse
);
}
void
handleOnDismissed
(
item
)
{
void
handleOnDismissed
(
i
nt
i
tem
)
{
expect
(
dismissedItems
.
contains
(
item
),
isFalse
);
dismissedItems
.
add
(
item
);
}
...
...
@@ -39,7 +39,7 @@ Widget widgetBuilder() {
return
new
Container
(
padding:
const
EdgeDims
.
all
(
10.0
),
child:
new
ScrollableList
<
int
>(
items:
[
0
,
1
,
2
,
3
,
4
].
where
((
int
i
)
=>
!
dismissedItems
.
contains
(
i
)).
toList
(),
items:
<
int
>
[
0
,
1
,
2
,
3
,
4
].
where
((
int
i
)
=>
!
dismissedItems
.
contains
(
i
)).
toList
(),
itemBuilder:
buildDismissableItem
,
scrollDirection:
scrollDirection
,
itemExtent:
itemExtent
...
...
@@ -56,25 +56,25 @@ void dismissElement(WidgetTester tester, Element itemElement, { DismissDirection
Point
upLocation
;
switch
(
gestureDirection
)
{
case
DismissDirection
.
left
:
// Note: getTopRight() returns a point that's just beyond
// itemWidget's right edge and outside the Dismissable event
// listener's bounds.
// getTopRight() returns a point that's just beyond itemWidget's right
// edge and outside the Dismissable event listener's bounds.
downLocation
=
tester
.
getTopRight
(
itemElement
)
+
const
Offset
(-
0.1
,
0.0
);
upLocation
=
tester
.
getTopLeft
(
itemElement
);
break
;
case
DismissDirection
.
right
:
downLocation
=
tester
.
getTopLeft
(
itemElement
);
// we do the same thing here to keep the test symmetric
downLocation
=
tester
.
getTopLeft
(
itemElement
)
+
const
Offset
(
0.1
,
0.0
);
upLocation
=
tester
.
getTopRight
(
itemElement
);
break
;
case
DismissDirection
.
up
:
// Note: getBottomLeft() returns a point that's just below
// itemWidget's bottom edge and outside the Dismissable event
// listener's bounds.
// getBottomLeft() returns a point that's just below itemWidget's bottom
// edge and outside the Dismissable event listener's bounds.
downLocation
=
tester
.
getBottomLeft
(
itemElement
)
+
const
Offset
(
0.0
,
-
0.1
);
upLocation
=
tester
.
getTopLeft
(
itemElement
);
break
;
case
DismissDirection
.
down
:
downLocation
=
tester
.
getTopLeft
(
itemElement
);
// again with doing the same here for symmetry
downLocation
=
tester
.
getTopLeft
(
itemElement
)
+
const
Offset
(
0.1
,
0.0
);
upLocation
=
tester
.
getBottomLeft
(
itemElement
);
break
;
default
:
...
...
@@ -96,9 +96,11 @@ void dismissItem(WidgetTester tester, int item, { DismissDirection gestureDirect
dismissElement
(
tester
,
itemElement
,
gestureDirection:
gestureDirection
);
tester
.
pumpWidget
(
widgetBuilder
());
// start the resize animation
tester
.
pumpWidget
(
widgetBuilder
(),
const
Duration
(
seconds:
1
));
// finish the resize animation
tester
.
pumpWidget
(
widgetBuilder
(),
const
Duration
(
seconds:
1
));
// dismiss
tester
.
pumpWidget
(
widgetBuilder
());
// start the slide
tester
.
pumpWidget
(
widgetBuilder
(),
const
Duration
(
seconds:
1
));
// finish the slide and start shrinking...
tester
.
pumpWidget
(
widgetBuilder
());
// first frame of shrinking animation
tester
.
pumpWidget
(
widgetBuilder
(),
const
Duration
(
seconds:
1
));
// finish the shrinking and call the callback...
tester
.
pumpWidget
(
widgetBuilder
());
// rebuild after the callback removes the entry
}
class
Test1215DismissableComponent
extends
StatelessComponent
{
...
...
@@ -229,8 +231,12 @@ void main() {
});
});
// This is a regression test for
// https://github.com/domokit/sky_engine/issues/1068
// This is a regression test for an fn2 bug where dragging a card caused an
// assert "'!_disqualifiedFromEverAppearingAgain' is not true". The old URL
// was https://github.com/domokit/sky_engine/issues/1068 but that issue is 404
// now since we migrated to the new repo. The bug was fixed by
// https://github.com/flutter/engine/pull/1134 at the time, and later made
// irrelevant by fn3, but just in case...
test
(
'Verify that drag-move events do not assert'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
scrollDirection
=
ScrollDirection
.
horizontal
;
...
...
@@ -255,8 +261,12 @@ void main() {
});
});
// This one is for
// https://github.com/flutter/engine/issues/1215
// This one is for a case where dssmissing a component above a previously
// dismissed component threw an exception, which was documented at the
// now-obsolete URL https://github.com/flutter/engine/issues/1215 (the URL
// died in the migration to the new repo). Don't copy this test; it doesn't
// actually remove the dismissed widget, which is a violation of the
// Dismissable contract. This is not an example of good practice.
test
(
'dismissing bottom then top (smoketest)'
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
Center
(
...
...
@@ -272,11 +282,13 @@ void main() {
expect
(
tester
.
findText
(
'1'
),
isNotNull
);
expect
(
tester
.
findText
(
'2'
),
isNotNull
);
dismissElement
(
tester
,
tester
.
findText
(
'2'
),
gestureDirection:
DismissDirection
.
right
);
tester
.
pump
(
new
Duration
(
seconds:
1
));
tester
.
pump
();
// start the slide away
tester
.
pump
(
new
Duration
(
seconds:
1
));
// finish the slide away
expect
(
tester
.
findText
(
'1'
),
isNotNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
dismissElement
(
tester
,
tester
.
findText
(
'1'
),
gestureDirection:
DismissDirection
.
right
);
tester
.
pump
(
new
Duration
(
seconds:
1
));
tester
.
pump
();
// start the slide away
tester
.
pump
(
new
Duration
(
seconds:
1
));
// finish the slide away (at which point the child is no longer included in the tree)
expect
(
tester
.
findText
(
'1'
),
isNull
);
expect
(
tester
.
findText
(
'2'
),
isNull
);
});
...
...
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