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
0377e80d
Unverified
Commit
0377e80d
authored
Sep 22, 2023
by
Tomasz Gucio
Committed by
GitHub
Sep 22, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Size CupertinoTextSelectionToolbar to children (#133386)
parent
85e52d43
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
253 additions
and
215 deletions
+253
-215
text_selection_toolbar.dart
...ges/flutter/lib/src/cupertino/text_selection_toolbar.dart
+222
-180
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+9
-9
text_selection_test.dart
packages/flutter/test/cupertino/text_selection_test.dart
+2
-2
text_selection_toolbar_test.dart
...s/flutter/test/cupertino/text_selection_toolbar_test.dart
+20
-24
No files found.
packages/flutter/lib/src/cupertino/text_selection_toolbar.dart
View file @
0377e80d
...
@@ -14,20 +14,25 @@ import 'colors.dart';
...
@@ -14,20 +14,25 @@ import 'colors.dart';
import
'text_selection_toolbar_button.dart'
;
import
'text_selection_toolbar_button.dart'
;
import
'theme.dart'
;
import
'theme.dart'
;
// Values extracted from https://developer.apple.com/design/resources/.
// The radius of the toolbar RRect shape.
// The height of the toolbar, including the arrow.
// Value extracted from https://developer.apple.com/design/resources/.
const
double
_kToolbarHeight
=
45.0
;
const
Radius
_kToolbarBorderRadius
=
Radius
.
circular
(
8.0
);
// Vertical distance between the tip of the arrow and the line of text the arrow
// Vertical distance between the tip of the arrow and the line of text the arrow
// is pointing to. The value used here is eyeballed.
// is pointing to. The value used here is eyeballed.
const
double
_kToolbarContentDistance
=
8.0
;
const
double
_kToolbarContentDistance
=
8.0
;
// The size of the arrow pointing to the anchor. Eyeballed value.
const
Size
_kToolbarArrowSize
=
Size
(
14.0
,
7.0
);
const
Size
_kToolbarArrowSize
=
Size
(
14.0
,
7.0
);
// Minimal padding from tip of the selection toolbar arrow to horizontal edges of the
// Minimal padding from tip of the selection toolbar arrow to horizontal edges of the
// screen. Eyeballed value.
// screen. Eyeballed value.
const
double
_kArrowScreenPadding
=
26.0
;
const
double
_kArrowScreenPadding
=
26.0
;
// Values extracted from https://developer.apple.com/design/resources/.
// The size and thickness of the chevron icon used for navigating between toolbar pages.
const
Radius
_kToolbarBorderRadius
=
Radius
.
circular
(
8
);
// Eyeballed values.
const
double
_kToolbarChevronSize
=
10.0
;
const
double
_kToolbarChevronThickness
=
2.0
;
// Color was measured from a screenshot of iOS 16.0.2
// Color was measured from a screenshot of iOS 16.0.2
// TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/41507.
// TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/41507.
...
@@ -36,9 +41,6 @@ const CupertinoDynamicColor _kToolbarBackgroundColor = CupertinoDynamicColor.wit
...
@@ -36,9 +41,6 @@ const CupertinoDynamicColor _kToolbarBackgroundColor = CupertinoDynamicColor.wit
darkColor:
Color
(
0xFF222222
),
darkColor:
Color
(
0xFF222222
),
);
);
const
double
_kToolbarChevronSize
=
10
;
const
double
_kToolbarChevronThickness
=
2
;
// Color was measured from a screenshot of iOS 16.0.2.
// Color was measured from a screenshot of iOS 16.0.2.
const
CupertinoDynamicColor
_kToolbarDividerColor
=
CupertinoDynamicColor
.
withBrightness
(
const
CupertinoDynamicColor
_kToolbarDividerColor
=
CupertinoDynamicColor
.
withBrightness
(
color:
Color
(
0xFFD6D6D6
),
color:
Color
(
0xFFD6D6D6
),
...
@@ -64,8 +66,8 @@ const Duration _kToolbarTransitionDuration = Duration(milliseconds: 125);
...
@@ -64,8 +66,8 @@ const Duration _kToolbarTransitionDuration = Duration(milliseconds: 125);
/// Material-style toolbar.
/// Material-style toolbar.
typedef
CupertinoToolbarBuilder
=
Widget
Function
(
typedef
CupertinoToolbarBuilder
=
Widget
Function
(
BuildContext
context
,
BuildContext
context
,
Offset
anchor
,
Offset
anchor
Above
,
bool
isAbove
,
Offset
anchorBelow
,
Widget
child
,
Widget
child
,
);
);
...
@@ -127,37 +129,23 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
...
@@ -127,37 +129,23 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
// Builds a toolbar just like the default iOS toolbar, with the right color
// Builds a toolbar just like the default iOS toolbar, with the right color
// background and a rounded cutout with an arrow.
// background and a rounded cutout with an arrow.
static
Widget
_defaultToolbarBuilder
(
BuildContext
context
,
Offset
anchor
,
bool
isAbove
,
Widget
child
)
{
static
Widget
_defaultToolbarBuilder
(
final
Widget
outputChild
=
_CupertinoTextSelectionToolbarShape
(
BuildContext
context
,
anchor:
anchor
,
Offset
anchorAbove
,
isAbove:
isAbove
,
Offset
anchorBelow
,
Widget
child
,
)
{
return
_CupertinoTextSelectionToolbarShape
(
anchorAbove:
anchorAbove
,
anchorBelow:
anchorBelow
,
shadowColor:
CupertinoTheme
.
brightnessOf
(
context
)
==
Brightness
.
light
?
CupertinoColors
.
black
.
withOpacity
(
0.2
)
:
null
,
child:
ColoredBox
(
child:
ColoredBox
(
color:
_kToolbarBackgroundColor
.
resolveFrom
(
context
),
color:
_kToolbarBackgroundColor
.
resolveFrom
(
context
),
child:
child
,
child:
child
,
),
),
);
);
if
(
CupertinoTheme
.
brightnessOf
(
context
)
==
Brightness
.
dark
)
{
return
outputChild
;
}
return
DecoratedBox
(
// These shadow values were eyeballed from a screenshot of iOS 16.3.1, as
// light mode didn't appear in the Apple design resources assets linked at
// the top of this file.
decoration:
BoxDecoration
(
borderRadius:
const
BorderRadius
.
all
(
_kToolbarBorderRadius
),
boxShadow:
<
BoxShadow
>[
BoxShadow
(
color:
CupertinoColors
.
black
.
withOpacity
(
0.2
),
blurRadius:
15.0
,
offset:
Offset
(
0.0
,
isAbove
?
0.0
:
_kToolbarArrowSize
.
height
,
),
),
],
),
child:
outputChild
,
);
}
}
@override
@override
...
@@ -166,10 +154,6 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
...
@@ -166,10 +154,6 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
final
EdgeInsets
mediaQueryPadding
=
MediaQuery
.
paddingOf
(
context
);
final
EdgeInsets
mediaQueryPadding
=
MediaQuery
.
paddingOf
(
context
);
final
double
paddingAbove
=
mediaQueryPadding
.
top
+
kToolbarScreenPadding
;
final
double
paddingAbove
=
mediaQueryPadding
.
top
+
kToolbarScreenPadding
;
final
double
toolbarHeightNeeded
=
paddingAbove
+
_kToolbarContentDistance
+
_kToolbarHeight
;
final
bool
fitsAbove
=
anchorAbove
.
dy
>=
toolbarHeightNeeded
;
// The arrow, which points to the anchor, has some margin so it can't get
// The arrow, which points to the anchor, has some margin so it can't get
// too close to the horizontal edges of the screen.
// too close to the horizontal edges of the screen.
...
@@ -196,11 +180,10 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
...
@@ -196,11 +180,10 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
delegate:
TextSelectionToolbarLayoutDelegate
(
delegate:
TextSelectionToolbarLayoutDelegate
(
anchorAbove:
anchorAboveAdjusted
,
anchorAbove:
anchorAboveAdjusted
,
anchorBelow:
anchorBelowAdjusted
,
anchorBelow:
anchorBelowAdjusted
,
fitsAbove:
fitsAbove
,
),
),
child:
_CupertinoTextSelectionToolbarContent
(
child:
_CupertinoTextSelectionToolbarContent
(
anchor
:
fitsAbove
?
anchorAboveAdjusted
:
anchorBelow
Adjusted
,
anchor
Above:
anchorAbove
Adjusted
,
isAbove:
fitsAbove
,
anchorBelow:
anchorBelowAdjusted
,
toolbarBuilder:
toolbarBuilder
,
toolbarBuilder:
toolbarBuilder
,
children:
children
,
children:
children
,
),
),
...
@@ -215,30 +198,32 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
...
@@ -215,30 +198,32 @@ class CupertinoTextSelectionToolbar extends StatelessWidget {
// The anchor should be in global coordinates.
// The anchor should be in global coordinates.
class
_CupertinoTextSelectionToolbarShape
extends
SingleChildRenderObjectWidget
{
class
_CupertinoTextSelectionToolbarShape
extends
SingleChildRenderObjectWidget
{
const
_CupertinoTextSelectionToolbarShape
({
const
_CupertinoTextSelectionToolbarShape
({
required
Offset
anchor
,
required
Offset
anchorAbove
,
required
bool
isAbove
,
required
Offset
anchorBelow
,
Color
?
shadowColor
,
super
.
child
,
super
.
child
,
})
:
_anchor
=
anchor
,
})
:
_anchorAbove
=
anchorAbove
,
_isAbove
=
isAbove
;
_anchorBelow
=
anchorBelow
,
_shadowColor
=
shadowColor
;
final
Offset
_anchor
;
// Whether the arrow should point down and be attached to the bottom
final
Offset
_anchorAbove
;
// of the toolbar, or point up and be attached to the top of the toolbar.
final
Offset
_anchorBelow
;
final
bool
_isAbove
;
final
Color
?
_shadowColor
;
@override
@override
_RenderCupertinoTextSelectionToolbarShape
createRenderObject
(
BuildContext
context
)
=>
_RenderCupertinoTextSelectionToolbarShape
(
_RenderCupertinoTextSelectionToolbarShape
createRenderObject
(
BuildContext
context
)
=>
_RenderCupertinoTextSelectionToolbarShape
(
_anchor
,
_anchorAbove
,
_isAbove
,
_anchorBelow
,
_shadowColor
,
null
,
null
,
);
);
@override
@override
void
updateRenderObject
(
BuildContext
context
,
_RenderCupertinoTextSelectionToolbarShape
renderObject
)
{
void
updateRenderObject
(
BuildContext
context
,
_RenderCupertinoTextSelectionToolbarShape
renderObject
)
{
renderObject
renderObject
..
anchor
=
_anchor
..
anchorAbove
=
_anchorAbove
..
isAbove
=
_isAbove
;
..
anchorBelow
=
_anchorBelow
..
shadowColor
=
_shadowColor
;
}
}
}
}
...
@@ -252,34 +237,47 @@ class _CupertinoTextSelectionToolbarShape extends SingleChildRenderObjectWidget
...
@@ -252,34 +237,47 @@ class _CupertinoTextSelectionToolbarShape extends SingleChildRenderObjectWidget
// on the necessary side.
// on the necessary side.
class
_RenderCupertinoTextSelectionToolbarShape
extends
RenderShiftedBox
{
class
_RenderCupertinoTextSelectionToolbarShape
extends
RenderShiftedBox
{
_RenderCupertinoTextSelectionToolbarShape
(
_RenderCupertinoTextSelectionToolbarShape
(
this
.
_anchor
,
this
.
_anchorAbove
,
this
.
_isAbove
,
this
.
_anchorBelow
,
this
.
_shadowColor
,
super
.
child
,
super
.
child
,
);
);
@override
@override
bool
get
isRepaintBoundary
=>
true
;
bool
get
isRepaintBoundary
=>
true
;
Offset
get
anchor
=>
_anchor
;
Offset
get
anchor
Above
=>
_anchorAbove
;
Offset
_anchor
;
Offset
_anchor
Above
;
set
anchor
(
Offset
value
)
{
set
anchor
Above
(
Offset
value
)
{
if
(
value
==
_anchor
)
{
if
(
value
==
_anchor
Above
)
{
return
;
return
;
}
}
_anchor
=
value
;
_anchor
Above
=
value
;
markNeedsLayout
();
markNeedsLayout
();
}
}
bool
get
isAbove
=>
_isAbove
;
Offset
get
anchorBelow
=>
_anchorBelow
;
bool
_isAbove
;
Offset
_anchorBelow
;
set
isAbove
(
bool
value
)
{
set
anchorBelow
(
Offset
value
)
{
if
(
_isAbove
==
value
)
{
if
(
value
==
_anchorBelow
)
{
return
;
return
;
}
}
_
isAbove
=
value
;
_
anchorBelow
=
value
;
markNeedsLayout
();
markNeedsLayout
();
}
}
Color
?
get
shadowColor
=>
_shadowColor
;
Color
?
_shadowColor
;
set
shadowColor
(
Color
?
value
)
{
if
(
value
==
_shadowColor
)
{
return
;
}
_shadowColor
=
value
;
markNeedsPaint
();
}
bool
get
isAbove
=>
anchorAbove
.
dy
>=
(
child
?.
size
.
height
??
0.0
)
-
_kToolbarArrowSize
.
height
*
2
;
@override
@override
void
performLayout
()
{
void
performLayout
()
{
final
RenderBox
?
child
=
this
.
child
;
final
RenderBox
?
child
=
this
.
child
;
...
@@ -287,26 +285,21 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -287,26 +285,21 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
return
;
return
;
}
}
// The child is tall enough to have the arrow clipped out of it on both sides
final
BoxConstraints
enforcedConstraint
=
BoxConstraints
(
// top and bottom. Since _kToolbarHeight includes the height of one arrow, the
// total height that the child is given is that plus one more arrow height.
// The extra height on the opposite side of the arrow will be clipped out. By
// using this approach, the buttons don't need any special padding that
// depends on isAbove.
final
BoxConstraints
heightConstraint
=
BoxConstraints
(
minHeight:
_kToolbarHeight
+
_kToolbarArrowSize
.
height
,
maxHeight:
_kToolbarHeight
+
_kToolbarArrowSize
.
height
,
minWidth:
_kToolbarArrowSize
.
width
+
_kToolbarBorderRadius
.
x
*
2
,
minWidth:
_kToolbarArrowSize
.
width
+
_kToolbarBorderRadius
.
x
*
2
,
).
enforce
(
constraints
.
loosen
());
).
enforce
(
constraints
.
loosen
());
child
.
layout
(
enforcedConstraint
,
parentUsesSize:
true
);
child
.
layout
(
heightConstraint
,
parentUsesSize:
true
);
// The buttons are padded on both top and bottom sufficiently to have
// the arrow clipped out of it on either side. By
// using this approach, the buttons don't need any special padding that
// depends on isAbove.
// The height of one arrow will be clipped off of the child, so adjust the
// The height of one arrow will be clipped off of the child, so adjust the
// size and position to remove that piece from the layout.
// size and position to remove that piece from the layout.
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
childParentData
.
offset
=
Offset
(
childParentData
.
offset
=
Offset
(
0.0
,
0.0
,
_
isAbove
?
-
_kToolbarArrowSize
.
height
:
0.0
,
isAbove
?
-
_kToolbarArrowSize
.
height
:
0.0
,
);
);
size
=
Size
(
size
=
Size
(
child
.
size
.
width
,
child
.
size
.
width
,
...
@@ -314,6 +307,13 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -314,6 +307,13 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
);
);
}
}
// Returns the RRect inside which the child is painted.
RRect
_shapeRRect
(
RenderBox
child
)
{
final
Rect
rect
=
Offset
(
0.0
,
_kToolbarArrowSize
.
height
)
&
Size
(
child
.
size
.
width
,
child
.
size
.
height
-
_kToolbarArrowSize
.
height
*
2
);
return
RRect
.
fromRectAndRadius
(
rect
,
_kToolbarBorderRadius
).
scaleRadii
();
}
// Adds the given `rrect` to the current `path`, starting from the last point
// Adds the given `rrect` to the current `path`, starting from the last point
// in `path` and ends after the last corner of the rrect (closest corner to
// in `path` and ends after the last corner of the rrect (closest corner to
// `startAngle` in the counterclockwise direction), without closing the path.
// `startAngle` in the counterclockwise direction), without closing the path.
...
@@ -328,7 +328,7 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -328,7 +328,7 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
// added, then this method returns the mutated path without closing it.
// added, then this method returns the mutated path without closing it.
static
Path
_addRRectToPath
(
Path
path
,
RRect
rrect
,
{
required
double
startAngle
})
{
static
Path
_addRRectToPath
(
Path
path
,
RRect
rrect
,
{
required
double
startAngle
})
{
const
double
halfPI
=
math
.
pi
/
2
;
const
double
halfPI
=
math
.
pi
/
2
;
assert
(
startAngle
%
halfPI
==
0
);
assert
(
startAngle
%
halfPI
==
0
.0
);
final
Rect
rect
=
rrect
.
outerRect
;
final
Rect
rect
=
rrect
.
outerRect
;
final
List
<(
Offset
,
Radius
)>
rrectCorners
=
<(
Offset
,
Radius
)>[
final
List
<(
Offset
,
Radius
)>
rrectCorners
=
<(
Offset
,
Radius
)>[
...
@@ -351,12 +351,8 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -351,12 +351,8 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
return
path
;
return
path
;
}
}
// The path is described in the toolbar's coordinate system.
// The path is described in the toolbar child's coordinate system.
Path
_clipPath
(
RenderBox
child
)
{
Path
_clipPath
(
RenderBox
child
,
RRect
rrect
)
{
final
Rect
rect
=
Offset
(
0.0
,
_isAbove
?
0
:
_kToolbarArrowSize
.
height
)
&
Size
(
size
.
width
,
size
.
height
-
_kToolbarArrowSize
.
height
);
final
RRect
rrect
=
RRect
.
fromRectAndRadius
(
rect
,
_kToolbarBorderRadius
).
scaleRadii
();
final
Path
path
=
Path
();
final
Path
path
=
Path
();
// If there isn't enough width for the arrow + radii, ignore the arrow.
// If there isn't enough width for the arrow + radii, ignore the arrow.
// Because of the constraints we gave children in performLayout, this should
// Because of the constraints we gave children in performLayout, this should
...
@@ -366,7 +362,7 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -366,7 +362,7 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
return
path
..
addRRect
(
rrect
);
return
path
..
addRRect
(
rrect
);
}
}
final
Offset
localAnchor
=
globalToLocal
(
_anchor
);
final
Offset
localAnchor
=
globalToLocal
(
isAbove
?
_anchorAbove
:
_anchorBelow
);
final
double
arrowTipX
=
clampDouble
(
final
double
arrowTipX
=
clampDouble
(
localAnchor
.
dx
,
localAnchor
.
dx
,
_kToolbarBorderRadius
.
x
+
_kToolbarArrowSize
.
width
/
2
,
_kToolbarBorderRadius
.
x
+
_kToolbarArrowSize
.
width
/
2
,
...
@@ -374,18 +370,22 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -374,18 +370,22 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
);
);
// Draw the path clockwise, starting from the beginning side of the arrow.
// Draw the path clockwise, starting from the beginning side of the arrow.
if
(
_isAbove
)
{
if
(
isAbove
)
{
final
double
arrowBaseY
=
child
.
size
.
height
-
_kToolbarArrowSize
.
height
;
final
double
arrowTipY
=
child
.
size
.
height
;
path
path
..
moveTo
(
arrowTipX
+
_kToolbarArrowSize
.
width
/
2
,
rect
.
bottom
)
// right side of the arrow triangle
..
moveTo
(
arrowTipX
+
_kToolbarArrowSize
.
width
/
2
,
arrowBaseY
)
// right side of the arrow triangle
..
lineTo
(
arrowTipX
,
rect
.
bottom
+
_kToolbarArrowSize
.
height
)
// The tip of the arrow
..
lineTo
(
arrowTipX
,
arrowTipY
)
// The tip of the arrow
..
lineTo
(
arrowTipX
-
_kToolbarArrowSize
.
width
/
2
,
rect
.
bottom
);
// left side of the arrow triangle
..
lineTo
(
arrowTipX
-
_kToolbarArrowSize
.
width
/
2
,
arrowBaseY
);
// left side of the arrow triangle
}
else
{
}
else
{
final
double
arrowBaseY
=
_kToolbarArrowSize
.
height
;
const
double
arrowTipY
=
0.0
;
path
path
..
moveTo
(
arrowTipX
-
_kToolbarArrowSize
.
width
/
2
,
rect
.
top
)
// right side of the arrow triangle
..
moveTo
(
arrowTipX
-
_kToolbarArrowSize
.
width
/
2
,
arrowBaseY
)
// right side of the arrow triangle
..
lineTo
(
arrowTipX
,
rect
.
top
)
// The tip of the arrow
..
lineTo
(
arrowTipX
,
arrowTipY
)
// The tip of the arrow
..
lineTo
(
arrowTipX
+
_kToolbarArrowSize
.
width
/
2
,
rect
.
top
);
// left side of the arrow triangle
..
lineTo
(
arrowTipX
+
_kToolbarArrowSize
.
width
/
2
,
arrowBaseY
);
// left side of the arrow triangle
}
}
final
double
startAngle
=
_
isAbove
?
math
.
pi
/
2
:
-
math
.
pi
/
2
;
final
double
startAngle
=
isAbove
?
math
.
pi
/
2
:
-
math
.
pi
/
2
;
return
_addRRectToPath
(
path
,
rrect
,
startAngle:
startAngle
)..
close
();
return
_addRRectToPath
(
path
,
rrect
,
startAngle:
startAngle
)..
close
();
}
}
...
@@ -395,12 +395,34 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -395,12 +395,34 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
if
(
child
==
null
)
{
if
(
child
==
null
)
{
return
;
return
;
}
}
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
final
RRect
rrect
=
_shapeRRect
(
child
);
final
Path
clipPath
=
_clipPath
(
child
,
rrect
);
// If configured, paint the shadow beneath the shape.
if
(
_shadowColor
!=
null
)
{
final
BoxShadow
boxShadow
=
BoxShadow
(
color:
_shadowColor
!,
blurRadius:
15.0
,
);
final
RRect
shadowRRect
=
RRect
.
fromLTRBR
(
rrect
.
left
,
rrect
.
top
,
rrect
.
right
,
rrect
.
bottom
+
_kToolbarArrowSize
.
height
,
_kToolbarBorderRadius
,
).
shift
(
offset
+
childParentData
.
offset
+
boxShadow
.
offset
);
context
.
canvas
.
drawRRect
(
shadowRRect
,
boxShadow
.
toPaint
());
}
_clipPathLayer
.
layer
=
context
.
pushClipPath
(
_clipPathLayer
.
layer
=
context
.
pushClipPath
(
needsCompositing
,
needsCompositing
,
offset
,
offset
+
childParentData
.
offset
,
Offset
.
zero
&
size
,
Offset
.
zero
&
child
.
size
,
_clipPath
(
child
)
,
clipPath
,
super
.
paint
,
(
PaintingContext
innerContext
,
Offset
innerOffset
)
=>
innerContext
.
paintChild
(
child
,
innerOffset
)
,
oldLayer:
_clipPathLayer
.
layer
,
oldLayer:
_clipPathLayer
.
layer
,
);
);
}
}
...
@@ -434,21 +456,27 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -434,21 +456,27 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
..
style
=
PaintingStyle
.
stroke
;
..
style
=
PaintingStyle
.
stroke
;
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
context
.
canvas
.
drawPath
(
_clipPath
(
child
).
shift
(
offset
+
childParentData
.
offset
),
debugPaint
);
final
Path
clipPath
=
_clipPath
(
child
,
_shapeRRect
(
child
));
context
.
canvas
.
drawPath
(
clipPath
.
shift
(
offset
+
childParentData
.
offset
),
debugPaint
);
return
true
;
return
true
;
}());
}());
}
}
@override
@override
bool
hitTestChildren
(
BoxHitTestResult
result
,
{
required
Offset
position
})
{
bool
hitTestChildren
(
BoxHitTestResult
result
,
{
required
Offset
position
})
{
final
RenderBox
?
child
=
this
.
child
;
if
(
child
==
null
)
{
return
false
;
}
// Positions outside of the clipped area of the child are not counted as
// Positions outside of the clipped area of the child are not counted as
// hits.
// hits.
final
BoxParentData
childParentData
=
child
!
.
parentData
!
as
BoxParentData
;
final
BoxParentData
childParentData
=
child
.
parentData
!
as
BoxParentData
;
final
Rect
hitBox
=
Rect
.
fromLTWH
(
final
Rect
hitBox
=
Rect
.
fromLTWH
(
childParentData
.
offset
.
dx
,
childParentData
.
offset
.
dx
,
childParentData
.
offset
.
dy
+
_kToolbarArrowSize
.
height
,
childParentData
.
offset
.
dy
+
_kToolbarArrowSize
.
height
,
child
!
.
size
.
width
,
child
.
size
.
width
,
child
!
.
size
.
height
-
_kToolbarArrowSize
.
height
*
2
,
child
.
size
.
height
-
_kToolbarArrowSize
.
height
*
2
,
);
);
if
(!
hitBox
.
contains
(
position
))
{
if
(!
hitBox
.
contains
(
position
))
{
return
false
;
return
false
;
...
@@ -465,15 +493,15 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
...
@@ -465,15 +493,15 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox {
// The anchor should be in global coordinates.
// The anchor should be in global coordinates.
class
_CupertinoTextSelectionToolbarContent
extends
StatefulWidget
{
class
_CupertinoTextSelectionToolbarContent
extends
StatefulWidget
{
const
_CupertinoTextSelectionToolbarContent
({
const
_CupertinoTextSelectionToolbarContent
({
required
this
.
anchor
,
required
this
.
anchor
Above
,
required
this
.
isAbove
,
required
this
.
anchorBelow
,
required
this
.
toolbarBuilder
,
required
this
.
toolbarBuilder
,
required
this
.
children
,
required
this
.
children
,
})
:
assert
(
children
.
length
>
0
);
})
:
assert
(
children
.
length
>
0
);
final
Offset
anchor
;
final
Offset
anchorAbove
;
final
Offset
anchorBelow
;
final
List
<
Widget
>
children
;
final
List
<
Widget
>
children
;
final
bool
isAbove
;
final
CupertinoToolbarBuilder
toolbarBuilder
;
final
CupertinoToolbarBuilder
toolbarBuilder
;
@override
@override
...
@@ -564,26 +592,48 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
...
@@ -564,26 +592,48 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
super
.
dispose
();
super
.
dispose
();
}
}
Widget
_createChevron
({
required
bool
isLeft
})
{
@override
final
Color
color
=
_kToolbarTextColor
.
resolveFrom
(
context
);
Widget
build
(
BuildContext
context
)
{
final
Color
chevronColor
=
_kToolbarTextColor
.
resolveFrom
(
context
);
return
IgnorePointer
(
child:
Center
(
// Wrap the children and the chevron painters in Center with widthFactor
// If widthFactor is not set to 0, the button is given unbounded width.
// and heightFactor of 1.0 so _CupertinoTextSelectionToolbarItems can get
widthFactor:
0
,
// the natural size of the buttons and then expand vertically as needed.
final
Widget
backButton
=
Center
(
widthFactor:
1.0
,
heightFactor:
1.0
,
child:
CupertinoTextSelectionToolbarButton
(
onPressed:
_handlePreviousPage
,
child:
IgnorePointer
(
child:
CustomPaint
(
child:
CustomPaint
(
painter:
isLeft
painter:
_LeftCupertinoChevronPainter
(
color:
chevronColor
),
?
_LeftCupertinoChevronPainter
(
color:
color
)
:
_RightCupertinoChevronPainter
(
color:
color
),
size:
const
Size
.
square
(
_kToolbarChevronSize
),
size:
const
Size
.
square
(
_kToolbarChevronSize
),
),
),
),
),
),
);
);
}
final
Widget
nextButton
=
Center
(
widthFactor:
1.0
,
heightFactor:
1.0
,
child:
CupertinoTextSelectionToolbarButton
(
onPressed:
_handleNextPage
,
child:
IgnorePointer
(
child:
CustomPaint
(
painter:
_RightCupertinoChevronPainter
(
color:
chevronColor
),
size:
const
Size
.
square
(
_kToolbarChevronSize
),
),
),
),
);
final
List
<
Widget
>
children
=
widget
.
children
.
map
((
Widget
child
)
{
return
Center
(
widthFactor:
1.0
,
heightFactor:
1.0
,
child:
child
,
);
}).
toList
();
@override
return
widget
.
toolbarBuilder
(
context
,
widget
.
anchorAbove
,
widget
.
anchorBelow
,
FadeTransition
(
Widget
build
(
BuildContext
context
)
{
return
widget
.
toolbarBuilder
(
context
,
widget
.
anchor
,
widget
.
isAbove
,
FadeTransition
(
opacity:
_controller
,
opacity:
_controller
,
child:
AnimatedSize
(
child:
AnimatedSize
(
duration:
_kToolbarTransitionDuration
,
duration:
_kToolbarTransitionDuration
,
...
@@ -593,17 +643,11 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
...
@@ -593,17 +643,11 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
child:
_CupertinoTextSelectionToolbarItems
(
child:
_CupertinoTextSelectionToolbarItems
(
key:
_toolbarItemsKey
,
key:
_toolbarItemsKey
,
page:
_page
,
page:
_page
,
backButton:
CupertinoTextSelectionToolbarButton
(
backButton:
backButton
,
onPressed:
_handlePreviousPage
,
child:
_createChevron
(
isLeft:
true
),
),
dividerColor:
_kToolbarDividerColor
.
resolveFrom
(
context
),
dividerColor:
_kToolbarDividerColor
.
resolveFrom
(
context
),
dividerWidth:
1.0
/
MediaQuery
.
devicePixelRatioOf
(
context
),
dividerWidth:
1.0
/
MediaQuery
.
devicePixelRatioOf
(
context
),
nextButton:
CupertinoTextSelectionToolbarButton
(
nextButton:
nextButton
,
onPressed:
_handleNextPage
,
children:
children
,
child:
_createChevron
(
isLeft:
false
),
),
children:
widget
.
children
,
),
),
),
),
),
),
...
@@ -633,7 +677,7 @@ abstract class _CupertinoChevronPainter extends CustomPainter {
...
@@ -633,7 +677,7 @@ abstract class _CupertinoChevronPainter extends CustomPainter {
@override
@override
void
paint
(
Canvas
canvas
,
Size
size
)
{
void
paint
(
Canvas
canvas
,
Size
size
)
{
assert
(
size
.
height
==
size
.
width
,
'size must have the same height and width'
);
assert
(
size
.
height
==
size
.
width
,
'size must have the same height and width
:
$size
'
);
final
double
iconSize
=
size
.
height
;
final
double
iconSize
=
size
.
height
;
...
@@ -893,10 +937,6 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
...
@@ -893,10 +937,6 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
return
newChild
;
return
newChild
;
}
}
bool
_isSlottedChild
(
RenderBox
child
)
{
return
child
==
_backButton
||
child
==
_nextButton
;
}
int
_page
;
int
_page
;
int
get
page
=>
_page
;
int
get
page
=>
_page
;
set
page
(
int
value
)
{
set
page
(
int
value
)
{
...
@@ -946,66 +986,71 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
...
@@ -946,66 +986,71 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
return
;
return
;
}
}
// First pass: determine the height of the tallest child.
double
greatestHeight
=
0.0
;
visitChildren
((
RenderObject
renderObjectChild
)
{
final
RenderBox
child
=
renderObjectChild
as
RenderBox
;
final
double
childHeight
=
child
.
getMaxIntrinsicHeight
(
constraints
.
maxWidth
);
if
(
childHeight
>
greatestHeight
)
{
greatestHeight
=
childHeight
;
}
});
// Layout slotted children.
// Layout slotted children.
_backButton
!.
layout
(
constraints
.
loosen
(),
parentUsesSize:
true
);
final
BoxConstraints
slottedConstraints
=
BoxConstraints
(
_nextButton
!.
layout
(
constraints
.
loosen
(),
parentUsesSize:
true
);
maxWidth:
constraints
.
maxWidth
,
minHeight:
greatestHeight
,
maxHeight:
greatestHeight
,
);
_backButton
!.
layout
(
slottedConstraints
,
parentUsesSize:
true
);
_nextButton
!.
layout
(
slottedConstraints
,
parentUsesSize:
true
);
final
double
subsequentPageButtonsWidth
=
final
double
subsequentPageButtonsWidth
=
_backButton
!.
size
.
width
+
_nextButton
!.
size
.
width
;
_backButton
!.
size
.
width
+
_nextButton
!.
size
.
width
;
double
currentButtonPosition
=
0.0
;
double
currentButtonPosition
=
0.0
;
late
double
toolbarWidth
;
// The width of the whole widget.
late
double
toolbarWidth
;
// The width of the whole widget.
late
double
greatestHeight
=
0.0
;
late
double
firstPageWidth
;
late
double
firstPageWidth
;
int
currentPage
=
0
;
int
currentPage
=
0
;
int
i
=
-
1
;
int
i
=
-
1
;
visitChildren
((
RenderObject
renderObjectChild
)
{
visitChildren
((
RenderObject
renderObjectChild
)
{
i
++;
i
++;
final
RenderBox
child
=
renderObjectChild
as
RenderBox
;
final
RenderBox
child
=
renderObjectChild
as
RenderBox
;
final
ToolbarItemsParentData
childParentData
=
final
ToolbarItemsParentData
childParentData
=
child
.
parentData
!
as
ToolbarItemsParentData
;
child
.
parentData
!
as
ToolbarItemsParentData
;
childParentData
.
shouldPaint
=
false
;
childParentData
.
shouldPaint
=
false
;
// Skip slotted children and children on pages after the visible page.
// Skip slotted children and children on pages after the visible page.
if
(
_isSlottedChild
(
child
)
||
currentPage
>
_page
)
{
if
(
child
==
_backButton
||
child
==
_nextButton
||
currentPage
>
_page
)
{
return
;
return
;
}
}
double
paginationButtonsWidth
=
0.0
;
// If this is the last child on the first page, it's ok to fit without a forward button.
if
(
currentPage
==
0
)
{
// If this is the last child, it's ok to fit without a forward button.
// Note childCount doesn't include slotted children which come before the list ones.
// Note childCount doesn't include slotted children which come before the list ones.
paginationButtonsWidth
=
double
paginationButtonsWidth
=
currentPage
==
0
i
==
childCount
+
1
?
0.0
:
_nextButton
!.
size
.
width
;
?
i
==
childCount
+
1
?
0.0
:
_nextButton
!.
size
.
width
}
else
{
:
subsequentPageButtonsWidth
;
paginationButtonsWidth
=
subsequentPageButtonsWidth
;
}
// The width of the menu is set by the first page.
// The width of the menu is set by the first page.
child
.
layout
(
child
.
layout
(
BoxConstraints
.
loose
(
Size
(
BoxConstraints
(
(
currentPage
==
0
?
constraints
.
maxWidth
:
firstPageWidth
)
-
paginationButtonsWidth
,
maxWidth:
(
currentPage
==
0
?
constraints
.
maxWidth
:
firstPageWidth
)
-
paginationButtonsWidth
,
constraints
.
maxHeight
,
minHeight:
greatestHeight
,
)),
maxHeight:
greatestHeight
,
),
parentUsesSize:
true
,
parentUsesSize:
true
,
);
);
greatestHeight
=
child
.
size
.
height
>
greatestHeight
?
child
.
size
.
height
:
greatestHeight
;
// If this child causes the current page to overflow, move to the next
// If this child causes the current page to overflow, move to the next
// page and relayout the child.
// page and relayout the child.
final
double
currentWidth
=
final
double
currentWidth
=
currentButtonPosition
+
paginationButtonsWidth
+
child
.
size
.
width
;
currentButtonPosition
+
paginationButtonsWidth
+
child
.
size
.
width
;
if
(
currentWidth
>
constraints
.
maxWidth
)
{
if
(
currentWidth
>
constraints
.
maxWidth
)
{
currentPage
++;
currentPage
++;
currentButtonPosition
=
_backButton
!.
size
.
width
+
dividerWidth
;
currentButtonPosition
=
_backButton
!.
size
.
width
+
dividerWidth
;
paginationButtonsWidth
=
_backButton
!.
size
.
width
+
_nextButton
!.
size
.
width
;
paginationButtonsWidth
=
_backButton
!.
size
.
width
+
_nextButton
!.
size
.
width
;
child
.
layout
(
child
.
layout
(
BoxConstraints
.
loose
(
Size
(
BoxConstraints
(
firstPageWidth
-
paginationButtonsWidth
,
maxWidth:
firstPageWidth
-
paginationButtonsWidth
,
constraints
.
maxHeight
,
minHeight:
greatestHeight
,
)),
maxHeight:
greatestHeight
,
),
parentUsesSize:
true
,
parentUsesSize:
true
,
);
);
}
}
...
@@ -1026,10 +1071,8 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
...
@@ -1026,10 +1071,8 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
// Position page nav buttons.
// Position page nav buttons.
if
(
currentPage
>
0
)
{
if
(
currentPage
>
0
)
{
final
ToolbarItemsParentData
nextButtonParentData
=
final
ToolbarItemsParentData
nextButtonParentData
=
_nextButton
!.
parentData
!
as
ToolbarItemsParentData
;
_nextButton
!.
parentData
!
as
ToolbarItemsParentData
;
final
ToolbarItemsParentData
backButtonParentData
=
_backButton
!.
parentData
!
as
ToolbarItemsParentData
;
final
ToolbarItemsParentData
backButtonParentData
=
_backButton
!.
parentData
!
as
ToolbarItemsParentData
;
// The forward button only shows when there's a page after this one.
// The forward button only shows when there's a page after this one.
if
(
page
!=
currentPage
)
{
if
(
page
!=
currentPage
)
{
nextButtonParentData
.
offset
=
Offset
(
toolbarWidth
,
0.0
);
nextButtonParentData
.
offset
=
Offset
(
toolbarWidth
,
0.0
);
...
@@ -1043,15 +1086,15 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
...
@@ -1043,15 +1086,15 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
// already been taken care of when laying out the children to
// already been taken care of when laying out the children to
// accommodate the back button.
// accommodate the back button.
}
}
}
else
{
// No divider for the next button when there's only one page.
toolbarWidth
-=
dividerWidth
;
}
// Update previous/next page values so that we can check in the horizontal
// Update previous/next page values so that we can check in the horizontal
// drag gesture callback if it's possible to navigate.
// drag gesture callback if it's possible to navigate.
hasNextPage
=
page
!=
currentPage
;
hasNextPage
=
page
!=
currentPage
;
hasPreviousPage
=
page
>
0
;
hasPreviousPage
=
page
>
0
;
}
else
{
// No divider for the next button when there's only one page.
toolbarWidth
-=
dividerWidth
;
}
size
=
constraints
.
constrain
(
Size
(
toolbarWidth
,
greatestHeight
));
size
=
constraints
.
constrain
(
Size
(
toolbarWidth
,
greatestHeight
));
}
}
...
@@ -1093,8 +1136,7 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
...
@@ -1093,8 +1136,7 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container
if
(
child
==
null
)
{
if
(
child
==
null
)
{
return
false
;
return
false
;
}
}
final
ToolbarItemsParentData
childParentData
=
final
ToolbarItemsParentData
childParentData
=
child
.
parentData
!
as
ToolbarItemsParentData
;
child
.
parentData
!
as
ToolbarItemsParentData
;
if
(!
childParentData
.
shouldPaint
)
{
if
(!
childParentData
.
shouldPaint
)
{
return
false
;
return
false
;
}
}
...
...
packages/flutter/test/cupertino/text_field_test.dart
View file @
0377e80d
...
@@ -6837,7 +6837,7 @@ void main() {
...
@@ -6837,7 +6837,7 @@ void main() {
includes:
<
Offset
>
[
includes:
<
Offset
>
[
// Expected center of the arrow. The arrow should stay clear of
// Expected center of the arrow. The arrow should stay clear of
// the edges of the selection toolbar.
// the edges of the selection toolbar.
Offset
(
26.0
,
bottomLeftSelectionPosition
.
dy
+
7.0
+
8.0
+
0.1
),
Offset
(
26.0
,
bottomLeftSelectionPosition
.
dy
+
8.0
+
0.1
),
],
],
),
),
),
),
...
@@ -6847,10 +6847,10 @@ void main() {
...
@@ -6847,10 +6847,10 @@ void main() {
find
.
byType
(
CupertinoTextSelectionToolbar
),
find
.
byType
(
CupertinoTextSelectionToolbar
),
paints
..
clipPath
(
paints
..
clipPath
(
pathMatcher:
PathBoundsMatcher
(
pathMatcher:
PathBoundsMatcher
(
topMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
7
+
8
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
8
,
epsilon:
0.01
),
leftMatcher:
moreOrLessEquals
(
8
),
leftMatcher:
moreOrLessEquals
(
8
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
bottomMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
8
+
4
5
,
epsilon:
0.01
),
bottomMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
8
+
4
4
,
epsilon:
0.01
),
),
),
),
),
);
);
...
@@ -6898,7 +6898,7 @@ void main() {
...
@@ -6898,7 +6898,7 @@ void main() {
],
],
includes:
<
Offset
>
[
includes:
<
Offset
>
[
// Expected center of the arrow.
// Expected center of the arrow.
Offset
(
400
-
26.0
,
bottomLeftSelectionPosition
.
dy
+
7
+
8
+
0.1
),
Offset
(
400
-
26.0
,
bottomLeftSelectionPosition
.
dy
+
8
+
0.1
),
],
],
),
),
),
),
...
@@ -6908,9 +6908,9 @@ void main() {
...
@@ -6908,9 +6908,9 @@ void main() {
find
.
byType
(
CupertinoTextSelectionToolbar
),
find
.
byType
(
CupertinoTextSelectionToolbar
),
paints
..
clipPath
(
paints
..
clipPath
(
pathMatcher:
PathBoundsMatcher
(
pathMatcher:
PathBoundsMatcher
(
topMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
7
+
8
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
8
,
epsilon:
0.01
),
rightMatcher:
moreOrLessEquals
(
400.0
-
8
),
rightMatcher:
moreOrLessEquals
(
400.0
-
8
),
bottomMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
8
+
4
5
,
epsilon:
0.01
),
bottomMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
+
8
+
4
4
,
epsilon:
0.01
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
),
),
),
),
...
@@ -6963,7 +6963,7 @@ void main() {
...
@@ -6963,7 +6963,7 @@ void main() {
paints
..
clipPath
(
paints
..
clipPath
(
pathMatcher:
PathBoundsMatcher
(
pathMatcher:
PathBoundsMatcher
(
bottomMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
-
8
-
lineHeight
,
epsilon:
0.01
),
bottomMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
-
8
-
lineHeight
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
-
8
-
lineHeight
-
4
5
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
bottomLeftSelectionPosition
.
dy
-
8
-
lineHeight
-
4
4
,
epsilon:
0.01
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
),
),
...
@@ -7032,7 +7032,7 @@ void main() {
...
@@ -7032,7 +7032,7 @@ void main() {
paints
..
clipPath
(
paints
..
clipPath
(
pathMatcher:
PathBoundsMatcher
(
pathMatcher:
PathBoundsMatcher
(
bottomMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
,
epsilon:
0.01
),
bottomMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
-
4
5
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
-
4
4
,
epsilon:
0.01
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
),
),
...
@@ -7105,7 +7105,7 @@ void main() {
...
@@ -7105,7 +7105,7 @@ void main() {
paints
..
clipPath
(
paints
..
clipPath
(
pathMatcher:
PathBoundsMatcher
(
pathMatcher:
PathBoundsMatcher
(
bottomMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
,
epsilon:
0.01
),
bottomMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
-
4
5
,
epsilon:
0.01
),
topMatcher:
moreOrLessEquals
(
selectionPosition
.
dy
-
8
-
lineHeight
-
4
4
,
epsilon:
0.01
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
rightMatcher:
lessThanOrEqualTo
(
400
-
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
leftMatcher:
greaterThanOrEqualTo
(
8
),
),
),
...
...
packages/flutter/test/cupertino/text_selection_test.dart
View file @
0377e80d
...
@@ -671,8 +671,8 @@ void main() {
...
@@ -671,8 +671,8 @@ void main() {
final
Offset
textFieldOffset
=
final
Offset
textFieldOffset
=
tester
.
getTopLeft
(
find
.
byType
(
CupertinoTextField
));
tester
.
getTopLeft
(
find
.
byType
(
CupertinoTextField
));
// 7.0 + 4
5.0 + 8.0 - 8.0 = _kToolbarArrowSize + _kToolbarH
eight + _kToolbarContentDistance - padding
// 7.0 + 4
4.0 + 8.0 - 8.0 = _kToolbarArrowSize + text_button_h
eight + _kToolbarContentDistance - padding
expect
(
selectionOffset
.
dy
+
7.0
+
4
5
.0
+
8.0
-
8.0
,
equals
(
textFieldOffset
.
dy
));
expect
(
selectionOffset
.
dy
+
7.0
+
4
4
.0
+
8.0
-
8.0
,
equals
(
textFieldOffset
.
dy
));
},
},
skip:
isBrowser
,
// [intended] the selection menu isn't required by web
skip:
isBrowser
,
// [intended] the selection menu isn't required by web
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
}),
variant:
const
TargetPlatformVariant
(<
TargetPlatform
>{
TargetPlatform
.
iOS
}),
...
...
packages/flutter/test/cupertino/text_selection_toolbar_test.dart
View file @
0377e80d
...
@@ -12,7 +12,7 @@ import '../widgets/editable_text_utils.dart' show textOffsetToPosition;
...
@@ -12,7 +12,7 @@ import '../widgets/editable_text_utils.dart' show textOffsetToPosition;
// These constants are copied from cupertino/text_selection_toolbar.dart.
// These constants are copied from cupertino/text_selection_toolbar.dart.
const
double
_kArrowScreenPadding
=
26.0
;
const
double
_kArrowScreenPadding
=
26.0
;
const
double
_kToolbarContentDistance
=
8.0
;
const
double
_kToolbarContentDistance
=
8.0
;
const
double
_kToolbarHeight
=
45.0
;
const
Size
_kToolbarArrowSize
=
Size
(
14.0
,
7.0
)
;
// A custom text selection menu that just displays a single custom button.
// A custom text selection menu that just displays a single custom button.
class
_CustomCupertinoTextSelectionControls
extends
CupertinoTextSelectionControls
{
class
_CustomCupertinoTextSelectionControls
extends
CupertinoTextSelectionControls
{
...
@@ -271,7 +271,7 @@ void main() {
...
@@ -271,7 +271,7 @@ void main() {
testWidgetsWithLeakTracking
(
'positions itself at anchorAbove if it fits'
,
(
WidgetTester
tester
)
async
{
testWidgetsWithLeakTracking
(
'positions itself at anchorAbove if it fits'
,
(
WidgetTester
tester
)
async
{
late
StateSetter
setState
;
late
StateSetter
setState
;
const
double
height
=
_kToolbarHeight
;
const
double
height
=
50.0
;
const
double
anchorBelowY
=
500.0
;
const
double
anchorBelowY
=
500.0
;
double
anchorAboveY
=
0.0
;
double
anchorAboveY
=
0.0
;
const
double
paddingAbove
=
12.0
;
const
double
paddingAbove
=
12.0
;
...
@@ -332,7 +332,7 @@ void main() {
...
@@ -332,7 +332,7 @@ void main() {
});
});
await
tester
.
pump
();
await
tester
.
pump
();
toolbarY
=
tester
.
getTopLeft
(
findToolbar
()).
dy
;
toolbarY
=
tester
.
getTopLeft
(
findToolbar
()).
dy
;
expect
(
toolbarY
,
equals
(
anchorAboveY
-
height
-
_kToolbarContentDistance
));
expect
(
toolbarY
,
equals
(
anchorAboveY
-
height
+
_kToolbarArrowSize
.
height
-
_kToolbarContentDistance
));
},
skip:
kIsWeb
);
// [intended] We do not use Flutter-rendered context menu on the Web.
},
skip:
kIsWeb
);
// [intended] We do not use Flutter-rendered context menu on the Web.
testWidgetsWithLeakTracking
(
'can create and use a custom toolbar'
,
(
WidgetTester
tester
)
async
{
testWidgetsWithLeakTracking
(
'can create and use a custom toolbar'
,
(
WidgetTester
tester
)
async
{
...
@@ -429,7 +429,7 @@ void main() {
...
@@ -429,7 +429,7 @@ void main() {
testWidgetsWithLeakTracking
(
'draws a shadow below the toolbar in light mode'
,
(
WidgetTester
tester
)
async
{
testWidgetsWithLeakTracking
(
'draws a shadow below the toolbar in light mode'
,
(
WidgetTester
tester
)
async
{
late
StateSetter
setState
;
late
StateSetter
setState
;
const
double
height
=
_kToolbarHeight
;
const
double
height
=
50.0
;
double
anchorAboveY
=
0.0
;
double
anchorAboveY
=
0.0
;
await
tester
.
pumpWidget
(
await
tester
.
pumpWidget
(
...
@@ -468,20 +468,15 @@ void main() {
...
@@ -468,20 +468,15 @@ void main() {
),
),
);
);
// When the toolbar is below the content, the shadow hangs below the entire
final
double
dividerWidth
=
1.0
/
tester
.
view
.
devicePixelRatio
;
// toolbar.
final
Finder
finder
=
find
.
descendant
(
expect
(
of:
find
.
byType
(
CupertinoTextSelectionToolbar
),
find
.
byType
(
CupertinoTextSelectionToolbar
),
matching:
find
.
byType
(
DecoratedBox
),
paints
..
rrect
(
rrect:
RRect
.
fromLTRBR
(
8.0
,
515.0
,
158.0
+
2
*
dividerWidth
,
558.0
,
const
Radius
.
circular
(
8.0
)),
color:
const
Color
(
0x33000000
),
),
);
);
expect
(
finder
,
findsOneWidget
);
DecoratedBox
decoratedBox
=
tester
.
widget
(
finder
.
first
);
BoxDecoration
boxDecoration
=
decoratedBox
.
decoration
as
BoxDecoration
;
List
<
BoxShadow
>?
shadows
=
boxDecoration
.
boxShadow
;
expect
(
shadows
,
isNotNull
);
expect
(
shadows
,
hasLength
(
1
));
BoxShadow
shadow
=
boxDecoration
.
boxShadow
!.
first
;
expect
(
shadow
.
offset
.
dy
,
equals
(
7.0
));
// When the toolbar is above the content, the shadow sits around the arrow
// When the toolbar is above the content, the shadow sits around the arrow
// with no offset.
// with no offset.
...
@@ -489,12 +484,13 @@ void main() {
...
@@ -489,12 +484,13 @@ void main() {
anchorAboveY
=
80.0
;
anchorAboveY
=
80.0
;
});
});
await
tester
.
pump
();
await
tester
.
pump
();
decoratedBox
=
tester
.
widget
(
finder
.
first
);
boxDecoration
=
decoratedBox
.
decoration
as
BoxDecoration
;
expect
(
shadows
=
boxDecoration
.
boxShadow
;
find
.
byType
(
CupertinoTextSelectionToolbar
),
expect
(
shadows
,
isNotNull
);
paints
..
rrect
(
expect
(
shadows
,
hasLength
(
1
));
rrect:
RRect
.
fromLTRBR
(
8.0
,
29.0
,
158.0
+
2
*
dividerWidth
,
72.0
,
const
Radius
.
circular
(
8.0
)),
shadow
=
boxDecoration
.
boxShadow
!.
first
;
color:
const
Color
(
0x33000000
),
expect
(
shadow
.
offset
.
dy
,
equals
(
0.0
));
),
);
},
skip:
kIsWeb
);
// [intended] We do not use Flutter-rendered context menu on the Web.
},
skip:
kIsWeb
);
// [intended] We do not use Flutter-rendered context menu on the Web.
}
}
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