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
492bfddd
Unverified
Commit
492bfddd
authored
Oct 10, 2022
by
chunhtai
Committed by
GitHub
Oct 10, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix selection area causes small scrollables to bounce (#112816)
parent
d03f6314
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
82 additions
and
24 deletions
+82
-24
scrollable.dart
packages/flutter/lib/src/widgets/scrollable.dart
+30
-18
scrollable_selection_test.dart
packages/flutter/test/widgets/scrollable_selection_test.dart
+52
-6
No files found.
packages/flutter/lib/src/widgets/scrollable.dart
View file @
492bfddd
...
...
@@ -989,6 +989,11 @@ class EdgeDraggingAutoScroller {
scrollRenderBox
.
getTransformTo
(
null
),
Rect
.
fromLTWH
(
0
,
0
,
scrollRenderBox
.
size
.
width
,
scrollRenderBox
.
size
.
height
)
);
assert
(
globalRect
.
size
.
width
>=
_dragTargetRelatedToScrollOrigin
.
size
.
width
&&
globalRect
.
size
.
height
>=
_dragTargetRelatedToScrollOrigin
.
size
.
height
,
'Drag target size is larger than scrollable size, which may cause bouncing'
,
);
_scrolling
=
true
;
double
?
newOffset
;
const
double
overDragMax
=
20.0
;
...
...
@@ -1000,23 +1005,27 @@ class EdgeDraggingAutoScroller {
final
double
proxyStart
=
_offsetExtent
(
_dragTargetRelatedToScrollOrigin
.
topLeft
,
_scrollDirection
);
final
double
proxyEnd
=
_offsetExtent
(
_dragTargetRelatedToScrollOrigin
.
bottomRight
,
_scrollDirection
);
late
double
overDrag
;
if
(
_axisDirection
==
AxisDirection
.
up
||
_axisDirection
==
AxisDirection
.
left
)
{
if
(
proxyEnd
>
viewportEnd
&&
scrollable
.
position
.
pixels
>
scrollable
.
position
.
minScrollExtent
)
{
overDrag
=
math
.
max
(
proxyEnd
-
viewportEnd
,
overDragMax
);
newOffset
=
math
.
max
(
scrollable
.
position
.
minScrollExtent
,
scrollable
.
position
.
pixels
-
overDrag
);
}
else
if
(
proxyStart
<
viewportStart
&&
scrollable
.
position
.
pixels
<
scrollable
.
position
.
maxScrollExtent
)
{
overDrag
=
math
.
max
(
viewportStart
-
proxyStart
,
overDragMax
);
newOffset
=
math
.
min
(
scrollable
.
position
.
maxScrollExtent
,
scrollable
.
position
.
pixels
+
overDrag
);
}
}
else
{
if
(
proxyStart
<
viewportStart
&&
scrollable
.
position
.
pixels
>
scrollable
.
position
.
minScrollExtent
)
{
overDrag
=
math
.
max
(
viewportStart
-
proxyStart
,
overDragMax
);
newOffset
=
math
.
max
(
scrollable
.
position
.
minScrollExtent
,
scrollable
.
position
.
pixels
-
overDrag
);
}
else
if
(
proxyEnd
>
viewportEnd
&&
scrollable
.
position
.
pixels
<
scrollable
.
position
.
maxScrollExtent
)
{
overDrag
=
math
.
max
(
proxyEnd
-
viewportEnd
,
overDragMax
);
newOffset
=
math
.
min
(
scrollable
.
position
.
maxScrollExtent
,
scrollable
.
position
.
pixels
+
overDrag
);
}
switch
(
_axisDirection
)
{
case
AxisDirection
.
up
:
case
AxisDirection
.
left
:
if
(
proxyEnd
>
viewportEnd
&&
scrollable
.
position
.
pixels
>
scrollable
.
position
.
minScrollExtent
)
{
final
double
overDrag
=
math
.
min
(
proxyEnd
-
viewportEnd
,
overDragMax
);
newOffset
=
math
.
max
(
scrollable
.
position
.
minScrollExtent
,
scrollable
.
position
.
pixels
-
overDrag
);
}
else
if
(
proxyStart
<
viewportStart
&&
scrollable
.
position
.
pixels
<
scrollable
.
position
.
maxScrollExtent
)
{
final
double
overDrag
=
math
.
min
(
viewportStart
-
proxyStart
,
overDragMax
);
newOffset
=
math
.
min
(
scrollable
.
position
.
maxScrollExtent
,
scrollable
.
position
.
pixels
+
overDrag
);
}
break
;
case
AxisDirection
.
right
:
case
AxisDirection
.
down
:
if
(
proxyStart
<
viewportStart
&&
scrollable
.
position
.
pixels
>
scrollable
.
position
.
minScrollExtent
)
{
final
double
overDrag
=
math
.
min
(
viewportStart
-
proxyStart
,
overDragMax
);
newOffset
=
math
.
max
(
scrollable
.
position
.
minScrollExtent
,
scrollable
.
position
.
pixels
-
overDrag
);
}
else
if
(
proxyEnd
>
viewportEnd
&&
scrollable
.
position
.
pixels
<
scrollable
.
position
.
maxScrollExtent
)
{
final
double
overDrag
=
math
.
min
(
proxyEnd
-
viewportEnd
,
overDragMax
);
newOffset
=
math
.
min
(
scrollable
.
position
.
maxScrollExtent
,
scrollable
.
position
.
pixels
+
overDrag
);
}
break
;
}
if
(
newOffset
==
null
||
(
newOffset
-
scrollable
.
position
.
pixels
).
abs
()
<
1.0
)
{
...
...
@@ -1055,7 +1064,10 @@ class _ScrollableSelectionContainerDelegate extends MultiSelectableSelectionCont
_position
.
addListener
(
_scheduleLayoutChange
);
}
static
const
double
_kDefaultDragTargetSize
=
200
;
// Pointer drag is a single point, it should not have a size.
static
const
double
_kDefaultDragTargetSize
=
0
;
// An eye-balled value for a smooth scrolling speed.
static
const
double
_kDefaultSelectToScrollVelocityScalar
=
30
;
final
ScrollableState
state
;
...
...
packages/flutter/test/widgets/scrollable_selection_test.dart
View file @
492bfddd
...
...
@@ -125,7 +125,8 @@ void main() {
expect
(
controller
.
offset
,
0.0
);
double
previousOffset
=
controller
.
offset
;
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
)));
// Scrollable only auto scroll if the drag passes the boundary.
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
))
+
const
Offset
(
0
,
20
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
controller
.
offset
>
previousOffset
,
isTrue
);
...
...
@@ -150,6 +151,50 @@ void main() {
await
gesture
.
up
();
});
testWidgets
(
'select to scroll works for small scrollable'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
controller
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
home:
SelectionArea
(
selectionControls:
materialTextSelectionControls
,
child:
Scaffold
(
body:
SizedBox
(
height:
10
,
child:
ListView
.
builder
(
controller:
controller
,
itemCount:
100
,
itemBuilder:
(
BuildContext
context
,
int
index
)
{
return
Text
(
'Item
$index
'
);
},
),
),
),
),
));
final
RenderParagraph
paragraph1
=
tester
.
renderObject
<
RenderParagraph
>(
find
.
descendant
(
of:
find
.
text
(
'Item 0'
),
matching:
find
.
byType
(
RichText
)));
final
TestGesture
gesture
=
await
tester
.
startGesture
(
textOffsetToPosition
(
paragraph1
,
2
),
kind:
ui
.
PointerDeviceKind
.
mouse
);
addTearDown
(
gesture
.
removePointer
);
await
tester
.
pump
();
expect
(
controller
.
offset
,
0.0
);
double
previousOffset
=
controller
.
offset
;
// Scrollable only auto scroll if the drag passes the boundary
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
))
+
const
Offset
(
0
,
20
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
expect
(
controller
.
offset
>
previousOffset
,
isTrue
);
previousOffset
=
controller
.
offset
;
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
milliseconds:
100
));
expect
(
controller
.
offset
>
previousOffset
,
isTrue
);
await
gesture
.
up
();
// Shouldn't be stuck if gesture is up.
await
tester
.
pumpAndSettle
(
const
Duration
(
seconds:
1
));
expect
(
tester
.
takeException
(),
isNull
);
});
testWidgets
(
'select to scroll backward'
,
(
WidgetTester
tester
)
async
{
final
ScrollController
controller
=
ScrollController
();
await
tester
.
pumpWidget
(
MaterialApp
(
...
...
@@ -174,7 +219,7 @@ void main() {
expect
(
controller
.
offset
,
4000
);
double
previousOffset
=
controller
.
offset
;
await
gesture
.
moveTo
(
tester
.
getTopLeft
(
find
.
byType
(
ListView
)));
await
gesture
.
moveTo
(
tester
.
getTopLeft
(
find
.
byType
(
ListView
))
+
const
Offset
(
0
,
-
20
)
);
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
controller
.
offset
<
previousOffset
,
isTrue
);
...
...
@@ -220,7 +265,8 @@ void main() {
expect
(
controller
.
offset
,
0.0
);
double
previousOffset
=
controller
.
offset
;
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
)));
// Scrollable only auto scroll if the drag passes the boundary
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
))
+
const
Offset
(
20
,
0
));
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
controller
.
offset
>
previousOffset
,
isTrue
);
...
...
@@ -268,7 +314,7 @@ void main() {
expect
(
controller
.
offset
,
2080
);
double
previousOffset
=
controller
.
offset
;
await
gesture
.
moveTo
(
tester
.
getTopLeft
(
find
.
byType
(
ListView
)));
await
gesture
.
moveTo
(
tester
.
getTopLeft
(
find
.
byType
(
ListView
))
+
const
Offset
(-
10
,
0
)
);
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
controller
.
offset
<
previousOffset
,
isTrue
);
...
...
@@ -427,8 +473,8 @@ void main() {
expect
(
controller
.
offset
,
0.0
);
double
previousOffset
=
controller
.
offset
;
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
)));
// Scrollable only auto scroll if the drag passes the boundary
await
gesture
.
moveTo
(
tester
.
getBottomRight
(
find
.
byType
(
ListView
))
+
const
Offset
(
0
,
40
)
);
await
tester
.
pump
();
await
tester
.
pump
(
const
Duration
(
seconds:
1
));
expect
(
controller
.
offset
>
previousOffset
,
isTrue
);
...
...
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