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
3b9b5ace
Unverified
Commit
3b9b5ace
authored
Jun 07, 2018
by
Michael Goderbauer
Committed by
GitHub
Jun 07, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
showOnScreen Improvements (#18252)
parent
c53245c6
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1463 additions
and
86 deletions
+1463
-86
list_wheel_viewport.dart
packages/flutter/lib/src/rendering/list_wheel_viewport.dart
+41
-17
object.dart
packages/flutter/lib/src/rendering/object.dart
+31
-6
viewport.dart
packages/flutter/lib/src/rendering/viewport.dart
+187
-48
viewport_offset.dart
packages/flutter/lib/src/rendering/viewport_offset.dart
+22
-1
scroll_position.dart
packages/flutter/lib/src/widgets/scroll_position.dart
+2
-1
single_child_scroll_view.dart
...ges/flutter/lib/src/widgets/single_child_scroll_view.dart
+33
-13
viewport_test.dart
packages/flutter/test/rendering/viewport_test.dart
+540
-0
list_wheel_scroll_view_test.dart
...ges/flutter/test/widgets/list_wheel_scroll_view_test.dart
+123
-0
single_child_scroll_view_test.dart
...s/flutter/test/widgets/single_child_scroll_view_test.dart
+484
-0
No files found.
packages/flutter/lib/src/rendering/list_wheel_viewport.dart
View file @
3b9b5ace
...
...
@@ -4,6 +4,7 @@
import
'dart:math'
as
math
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:vector_math/vector_math_64.dart'
show
Matrix4
;
...
...
@@ -614,27 +615,50 @@ class RenderListWheelViewport
}
@override
double
getOffsetToReveal
(
RenderObject
target
,
double
alignment
)
{
final
ListWheelParentData
parentData
=
target
.
parentData
;
final
double
centerPosition
=
parentData
.
offset
.
dy
;
if
(
alignment
<
0.5
)
{
return
centerPosition
+
_topScrollMarginExtent
*
alignment
*
2.0
;
}
else
if
(
alignment
>
0.5
)
{
return
centerPosition
-
_topScrollMarginExtent
*
(
alignment
-
0.5
)
*
2.0
;
}
else
{
return
centerPosition
;
}
RevealedOffset
getOffsetToReveal
(
RenderObject
target
,
double
alignment
,
{
Rect
rect
})
{
// `target` is only fully revealed when in the selected/center position. Therefore,
// this method always returns the offset that shows `target` in the center position,
// which is the same offset for all `alignment` values.
rect
??=
target
.
paintBounds
;
// `child` will be the last RenderObject before the viewport when walking up from `target`.
RenderObject
child
=
target
;
while
(
child
.
parent
!=
this
)
child
=
child
.
parent
;
final
ListWheelParentData
parentData
=
child
.
parentData
;
final
double
targetOffset
=
parentData
.
offset
.
dy
;
// the so-called "centerPosition"
final
Matrix4
transform
=
target
.
getTransformTo
(
this
);
final
Rect
bounds
=
MatrixUtils
.
transformRect
(
transform
,
rect
);
final
Rect
targetRect
=
bounds
.
translate
(
0.0
,
(
size
.
height
-
itemExtent
)
/
2
);
return
new
RevealedOffset
(
offset:
targetOffset
,
rect:
targetRect
);
}
@override
void
showOnScreen
([
RenderObject
child
])
{
if
(
child
!=
null
)
{
// Shows the child in the selected/center position.
offset
.
jumpTo
(
getOffsetToReveal
(
child
,
0.5
));
void
showOnScreen
({
RenderObject
descendant
,
Rect
rect
,
Duration
duration
=
Duration
.
zero
,
Curve
curve
=
Curves
.
ease
,
})
{
if
(
descendant
!=
null
)
{
// Shows the descendant in the selected/center position.
final
RevealedOffset
revealedOffset
=
getOffsetToReveal
(
descendant
,
0.5
,
rect:
rect
);
if
(
duration
==
Duration
.
zero
)
{
offset
.
jumpTo
(
revealedOffset
.
offset
);
}
else
{
offset
.
animateTo
(
revealedOffset
.
offset
,
duration:
duration
,
curve:
curve
);
}
rect
=
revealedOffset
.
rect
;
}
// Make sure the viewport itself is on screen.
super
.
showOnScreen
();
super
.
showOnScreen
(
rect:
rect
,
duration:
duration
,
curve:
curve
,
);
}
}
packages/flutter/lib/src/rendering/object.dart
View file @
3b9b5ace
...
...
@@ -5,6 +5,7 @@
import
'dart:developer'
;
import
'dart:ui'
as
ui
show
PictureRecorder
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/painting.dart'
;
...
...
@@ -2036,6 +2037,9 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
/// An estimate of the bounds within which this render object will paint.
/// Useful for debugging flags such as [debugPaintLayerBordersEnabled].
///
/// These are also the bounds used by [showOnScreen] to make a [RenderObject]
/// visible on screen.
Rect
get
paintBounds
;
/// Override this method to paint debugging information.
...
...
@@ -2570,14 +2574,35 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
@override
List
<
DiagnosticsNode
>
debugDescribeChildren
()
=>
<
DiagnosticsNode
>[];
/// Attempt to make this or a descendant RenderObject visible on screen.
///
/// If [child] is provided, that [RenderObject] is made visible. If [child] is
/// omitted, this [RenderObject] is made visible.
void
showOnScreen
([
RenderObject
child
])
{
/// Attempt to make (a portion of) this or a descendant [RenderObject] visible
/// on screen.
///
/// If `descendant` is provided, that [RenderObject] is made visible. If
/// `descendant` is omitted, this [RenderObject] is made visible.
///
/// The optional `rect` parameter describes which area of that [RenderObject]
/// should be shown on screen. If `rect` is null, the entire
/// [RenderObject] (as defined by its [paintBounds]) will be revealed. The
/// `rect` parameter is interpreted relative to the coordinate system of
/// `descendant` if that argument is provided and relative to this
/// [RenderObject] otherwise.
///
/// The `duration` parameter can be set to a non-zero value to bring the
/// target object on screen in an animation defined by `curve`.
void
showOnScreen
({
RenderObject
descendant
,
Rect
rect
,
Duration
duration
=
Duration
.
zero
,
Curve
curve
=
Curves
.
ease
,
})
{
if
(
parent
is
RenderObject
)
{
final
RenderObject
renderParent
=
parent
;
renderParent
.
showOnScreen
(
child
??
this
);
renderParent
.
showOnScreen
(
descendant:
descendant
??
this
,
rect:
rect
,
duration:
duration
,
curve:
curve
,
);
}
}
}
...
...
packages/flutter/lib/src/rendering/viewport.dart
View file @
3b9b5ace
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/rendering/viewport_offset.dart
View file @
3b9b5ace
...
...
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:async'
;
import
'package:flutter/animation.dart'
;
import
'package:flutter/foundation.dart'
;
/// The direction of a scroll, relative to the positive scroll offset axis given
...
...
@@ -157,7 +160,7 @@ abstract class ViewportOffset extends ChangeNotifier {
/// [jumpTo] applies the change immediately and notifies its listeners.
void
correctBy
(
double
correction
);
/// Jumps
the scroll position
from its current value to the given value,
/// Jumps
[pixels]
from its current value to the given value,
/// without animation, and without checking if the new value is in range.
///
/// See also:
...
...
@@ -166,6 +169,18 @@ abstract class ViewportOffset extends ChangeNotifier {
/// and that defers the notification of its listeners until after layout.
void
jumpTo
(
double
pixels
);
/// Animates [pixels] from its current value to the given value.
///
/// The returned [Future] will complete when the animation ends, whether it
/// completed successfully or whether it was interrupted prematurely.
///
/// The duration must not be zero. To jump to a particular value without an
/// animation, use [jumpTo].
Future
<
Null
>
animateTo
(
double
to
,
{
@required
Duration
duration
,
@required
Curve
curve
,
});
/// The direction in which the user is trying to change [pixels], relative to
/// the viewport's [RenderViewport.axisDirection].
///
...
...
@@ -227,6 +242,12 @@ class _FixedViewportOffset extends ViewportOffset {
// Do nothing, viewport is fixed.
}
@override
Future
<
Null
>
animateTo
(
double
to
,
{
@required
Duration
duration
,
@required
Curve
curve
,
})
async
=>
null
;
@override
ScrollDirection
get
userScrollDirection
=>
ScrollDirection
.
idle
;
}
packages/flutter/lib/src/widgets/scroll_position.dart
View file @
3b9b5ace
...
...
@@ -497,7 +497,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
final
RenderAbstractViewport
viewport
=
RenderAbstractViewport
.
of
(
object
);
assert
(
viewport
!=
null
);
final
double
target
=
viewport
.
getOffsetToReveal
(
object
,
alignment
).
clamp
(
minScrollExtent
,
maxScrollExtent
);
final
double
target
=
viewport
.
getOffsetToReveal
(
object
,
alignment
).
offset
.
clamp
(
minScrollExtent
,
maxScrollExtent
);
if
(
target
==
pixels
)
return
new
Future
<
Null
>.
value
();
...
...
@@ -544,6 +544,7 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
/// animation, use [jumpTo].
///
/// The animation is typically handled by an [DrivenScrollActivity].
@override
Future
<
Null
>
animateTo
(
double
to
,
{
@required
Duration
duration
,
@required
Curve
curve
,
...
...
packages/flutter/lib/src/widgets/single_child_scroll_view.dart
View file @
3b9b5ace
...
...
@@ -484,17 +484,19 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
offset
.
applyContentDimensions
(
_minScrollExtent
,
_maxScrollExtent
);
}
Offset
get
_paintOffset
{
Offset
get
_paintOffset
=>
_paintOffsetForPosition
(
offset
.
pixels
);
Offset
_paintOffsetForPosition
(
double
position
)
{
assert
(
axisDirection
!=
null
);
switch
(
axisDirection
)
{
case
AxisDirection
.
up
:
return
new
Offset
(
0.0
,
_offset
.
pixels
-
child
.
size
.
height
+
size
.
height
);
return
new
Offset
(
0.0
,
position
-
child
.
size
.
height
+
size
.
height
);
case
AxisDirection
.
down
:
return
new
Offset
(
0.0
,
-
_offset
.
pixels
);
return
new
Offset
(
0.0
,
-
position
);
case
AxisDirection
.
left
:
return
new
Offset
(
_offset
.
pixels
-
child
.
size
.
width
+
size
.
width
,
0.0
);
return
new
Offset
(
position
-
child
.
size
.
width
+
size
.
width
,
0.0
);
case
AxisDirection
.
right
:
return
new
Offset
(-
_offset
.
pixels
,
0.0
);
return
new
Offset
(-
position
,
0.0
);
}
return
null
;
}
...
...
@@ -544,13 +546,14 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
}
@override
double
getOffsetToReveal
(
RenderObject
target
,
double
alignment
)
{
RevealedOffset
getOffsetToReveal
(
RenderObject
target
,
double
alignment
,
{
Rect
rect
})
{
rect
??=
target
.
paintBounds
;
if
(
target
is
!
RenderBox
)
return
offset
.
pixels
;
return
new
RevealedOffset
(
offset:
offset
.
pixels
,
rect:
rect
)
;
final
RenderBox
targetBox
=
target
;
final
Matrix4
transform
=
targetBox
.
getTransformTo
(
this
);
final
Rect
bounds
=
MatrixUtils
.
transformRect
(
transform
,
targetBox
.
paintBounds
);
final
Rect
bounds
=
MatrixUtils
.
transformRect
(
transform
,
rect
);
final
Size
contentSize
=
child
.
size
;
double
leadingScrollOffset
;
...
...
@@ -581,14 +584,31 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
break
;
}
return
leadingScrollOffset
-
(
mainAxisExtent
-
targetMainAxisExtent
)
*
alignment
;
final
double
targetOffset
=
leadingScrollOffset
-
(
mainAxisExtent
-
targetMainAxisExtent
)
*
alignment
;
final
Rect
targetRect
=
bounds
.
shift
(
_paintOffsetForPosition
(
targetOffset
));
return
new
RevealedOffset
(
offset:
targetOffset
,
rect:
targetRect
);
}
@override
void
showOnScreen
([
RenderObject
child
])
{
RenderViewportBase
.
showInViewport
(
child:
child
,
viewport:
this
,
offset:
offset
);
// Make sure the viewport itself is on screen.
super
.
showOnScreen
();
void
showOnScreen
({
RenderObject
descendant
,
Rect
rect
,
Duration
duration
=
Duration
.
zero
,
Curve
curve
=
Curves
.
ease
,
})
{
final
Rect
newRect
=
RenderViewportBase
.
showInViewport
(
descendant:
descendant
,
viewport:
this
,
offset:
offset
,
rect:
rect
,
duration:
duration
,
curve:
curve
,
);
super
.
showOnScreen
(
rect:
newRect
,
duration:
duration
,
curve:
curve
,
);
}
@override
...
...
packages/flutter/test/rendering/viewport_test.dart
0 → 100644
View file @
3b9b5ace
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
View file @
3b9b5ace
...
...
@@ -743,4 +743,127 @@ void main() {
debugDefaultTargetPlatformOverride
=
null
;
});
});
testWidgets
(
'ListWheelScrollView getOffsetToReveal'
,
(
WidgetTester
tester
)
async
{
List
<
Widget
>
outerChildren
;
final
List
<
Widget
>
innerChildren
=
new
List
<
Widget
>(
10
);
await
tester
.
pumpWidget
(
new
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
new
Center
(
child:
Container
(
height:
500.0
,
width:
300.0
,
child:
new
ListWheelScrollView
(
controller:
new
ScrollController
(
initialScrollOffset:
300.0
),
itemExtent:
100.0
,
children:
outerChildren
=
new
List
<
Widget
>.
generate
(
10
,
(
int
i
)
{
return
new
Container
(
child:
new
Center
(
child:
innerChildren
[
i
]
=
new
Container
(
height:
50.0
,
width:
50.0
,
child:
new
Text
(
'Item
$i
'
),
),
),
);
}),
),
),
),
),
);
final
RenderListWheelViewport
viewport
=
tester
.
allRenderObjects
.
firstWhere
((
RenderObject
r
)
=>
r
is
RenderListWheelViewport
);
// direct child of viewport
RenderObject
target
=
tester
.
renderObject
(
find
.
byWidget
(
outerChildren
[
5
]));
RevealedOffset
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
);
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
0.0
,
200.0
,
300.0
,
100.0
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
0.0
,
200.0
,
300.0
,
100.0
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
new
Rect
.
fromLTWH
(
40.0
,
40.0
,
10.0
,
10.0
));
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
40.0
,
240.0
,
10.0
,
10.0
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
new
Rect
.
fromLTWH
(
40.0
,
40.0
,
10.0
,
10.0
));
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
40.0
,
240.0
,
10.0
,
10.0
));
// descendant of viewport, not direct child
target
=
tester
.
renderObject
(
find
.
byWidget
(
innerChildren
[
5
]));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
);
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
125.0
,
225.0
,
50.0
,
50.0
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
);
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
125.0
,
225.0
,
50.0
,
50.0
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
0.0
,
rect:
new
Rect
.
fromLTWH
(
40.0
,
40.0
,
10.0
,
10.0
));
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
165.0
,
265.0
,
10.0
,
10.0
));
revealed
=
viewport
.
getOffsetToReveal
(
target
,
1.0
,
rect:
new
Rect
.
fromLTWH
(
40.0
,
40.0
,
10.0
,
10.0
));
expect
(
revealed
.
offset
,
500.0
);
expect
(
revealed
.
rect
,
new
Rect
.
fromLTWH
(
165.0
,
265.0
,
10.0
,
10.0
));
});
testWidgets
(
'ListWheelScrollView showOnScreen'
,
(
WidgetTester
tester
)
async
{
List
<
Widget
>
outerChildren
;
final
List
<
Widget
>
innerChildren
=
new
List
<
Widget
>(
10
);
ScrollController
controller
;
await
tester
.
pumpWidget
(
new
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
new
Center
(
child:
Container
(
height:
500.0
,
width:
300.0
,
child:
new
ListWheelScrollView
(
controller:
controller
=
new
ScrollController
(
initialScrollOffset:
300.0
),
itemExtent:
100.0
,
children:
outerChildren
=
new
List
<
Widget
>.
generate
(
10
,
(
int
i
)
{
return
new
Container
(
child:
new
Center
(
child:
innerChildren
[
i
]
=
new
Container
(
height:
50.0
,
width:
50.0
,
child:
new
Text
(
'Item
$i
'
),
),
),
);
}),
),
),
),
),
);
expect
(
controller
.
offset
,
300.0
);
tester
.
renderObject
(
find
.
byWidget
(
outerChildren
[
5
])).
showOnScreen
();
await
tester
.
pumpAndSettle
();
expect
(
controller
.
offset
,
500.0
);
tester
.
renderObject
(
find
.
byWidget
(
innerChildren
[
9
])).
showOnScreen
();
await
tester
.
pumpAndSettle
();
expect
(
controller
.
offset
,
900.0
);
tester
.
renderObject
(
find
.
byWidget
(
outerChildren
[
7
])).
showOnScreen
(
duration:
const
Duration
(
seconds:
2
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
tester
.
hasRunningAnimations
,
isTrue
);
expect
(
controller
.
offset
,
lessThan
(
900.0
));
expect
(
controller
.
offset
,
greaterThan
(
700.0
));
await
tester
.
pumpAndSettle
();
expect
(
controller
.
offset
,
700.0
);
});
}
packages/flutter/test/widgets/single_child_scroll_view_test.dart
View file @
3b9b5ace
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