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
a395c952
Unverified
Commit
a395c952
authored
Nov 19, 2021
by
Rami
Committed by
GitHub
Nov 19, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support for MaterialTapTargetSize within ToggleButtons (#93259)
parent
ca14d85c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
251 additions
and
1 deletion
+251
-1
toggle_buttons.dart
packages/flutter/lib/src/material/toggle_buttons.dart
+161
-1
toggle_buttons_test.dart
packages/flutter/test/material/toggle_buttons_test.dart
+90
-0
No files found.
packages/flutter/lib/src/material/toggle_buttons.dart
View file @
a395c952
...
...
@@ -172,6 +172,7 @@ class ToggleButtons extends StatelessWidget {
required
this
.
isSelected
,
this
.
onPressed
,
this
.
mouseCursor
,
this
.
tapTargetSize
,
this
.
textStyle
,
this
.
constraints
,
this
.
color
,
...
...
@@ -231,6 +232,15 @@ class ToggleButtons extends StatelessWidget {
/// {@macro flutter.material.RawMaterialButton.mouseCursor}
final
MouseCursor
?
mouseCursor
;
/// Configures the minimum size of the area within which the buttons may
/// be pressed.
///
/// If the [tapTargetSize] is larger than [constraints], the buttons will
/// include a transparent margin that responds to taps.
///
/// Defaults to [ThemeData.materialTapTargetSize].
final
MaterialTapTargetSize
?
tapTargetSize
;
/// The [TextStyle] to apply to any text in these toggle buttons.
///
/// [TextStyle.color] will be ignored and substituted by [color],
...
...
@@ -686,7 +696,7 @@ class ToggleButtons extends StatelessWidget {
);
});
return
direction
==
Axis
.
horizontal
final
Widget
result
=
direction
==
Axis
.
horizontal
?
IntrinsicHeight
(
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
...
...
@@ -702,6 +712,18 @@ class ToggleButtons extends StatelessWidget {
children:
buttons
,
),
);
final
MaterialTapTargetSize
resolvedTapTargetSize
=
tapTargetSize
??
theme
.
materialTapTargetSize
;
switch
(
resolvedTapTargetSize
)
{
case
MaterialTapTargetSize
.
padded
:
return
_InputPadding
(
minSize:
const
Size
(
kMinInteractiveDimension
,
kMinInteractiveDimension
),
direction:
direction
,
child:
result
,
);
case
MaterialTapTargetSize
.
shrinkWrap
:
return
result
;
}
}
@override
...
...
@@ -1550,3 +1572,141 @@ class _SelectToggleButtonRenderObject extends RenderShiftedBox {
}
}
}
/// A widget to pad the area around a [ToggleButtons]'s children.
///
/// This widget is based on a similar one used in [ButtonStyleButton] but it
/// only redirects taps along one axis to ensure the correct button is tapped
/// within the [ToggleButtons].
///
/// This ensures that a widget takes up at least as much space as the minSize
/// parameter to ensure adequate tap target size, while keeping the widget
/// visually smaller to the user.
class
_InputPadding
extends
SingleChildRenderObjectWidget
{
const
_InputPadding
({
Key
?
key
,
Widget
?
child
,
required
this
.
minSize
,
required
this
.
direction
,
})
:
super
(
key:
key
,
child:
child
);
final
Size
minSize
;
final
Axis
direction
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
return
_RenderInputPadding
(
minSize
,
direction
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
_RenderInputPadding
renderObject
)
{
renderObject
.
minSize
=
minSize
;
renderObject
.
direction
=
direction
;
}
}
class
_RenderInputPadding
extends
RenderShiftedBox
{
_RenderInputPadding
(
this
.
_minSize
,
this
.
_direction
,
[
RenderBox
?
child
])
:
super
(
child
);
Size
get
minSize
=>
_minSize
;
Size
_minSize
;
set
minSize
(
Size
value
)
{
if
(
_minSize
==
value
)
return
;
_minSize
=
value
;
markNeedsLayout
();
}
Axis
get
direction
=>
_direction
;
Axis
_direction
;
set
direction
(
Axis
value
)
{
if
(
_direction
==
value
)
return
;
_direction
=
value
;
markNeedsLayout
();
}
@override
double
computeMinIntrinsicWidth
(
double
height
)
{
if
(
child
!=
null
)
return
math
.
max
(
child
!.
getMinIntrinsicWidth
(
height
),
minSize
.
width
);
return
0.0
;
}
@override
double
computeMinIntrinsicHeight
(
double
width
)
{
if
(
child
!=
null
)
return
math
.
max
(
child
!.
getMinIntrinsicHeight
(
width
),
minSize
.
height
);
return
0.0
;
}
@override
double
computeMaxIntrinsicWidth
(
double
height
)
{
if
(
child
!=
null
)
return
math
.
max
(
child
!.
getMaxIntrinsicWidth
(
height
),
minSize
.
width
);
return
0.0
;
}
@override
double
computeMaxIntrinsicHeight
(
double
width
)
{
if
(
child
!=
null
)
return
math
.
max
(
child
!.
getMaxIntrinsicHeight
(
width
),
minSize
.
height
);
return
0.0
;
}
Size
_computeSize
({
required
BoxConstraints
constraints
,
required
ChildLayouter
layoutChild
})
{
if
(
child
!=
null
)
{
final
Size
childSize
=
layoutChild
(
child
!,
constraints
);
final
double
height
=
math
.
max
(
childSize
.
width
,
minSize
.
width
);
final
double
width
=
math
.
max
(
childSize
.
height
,
minSize
.
height
);
return
constraints
.
constrain
(
Size
(
height
,
width
));
}
return
Size
.
zero
;
}
@override
Size
computeDryLayout
(
BoxConstraints
constraints
)
{
return
_computeSize
(
constraints:
constraints
,
layoutChild:
ChildLayoutHelper
.
dryLayoutChild
,
);
}
@override
void
performLayout
()
{
size
=
_computeSize
(
constraints:
constraints
,
layoutChild:
ChildLayoutHelper
.
layoutChild
,
);
if
(
child
!=
null
)
{
final
BoxParentData
childParentData
=
child
!.
parentData
!
as
BoxParentData
;
childParentData
.
offset
=
Alignment
.
center
.
alongOffset
(
size
-
child
!.
size
as
Offset
);
}
}
@override
bool
hitTest
(
BoxHitTestResult
result
,
{
required
Offset
position
})
{
// The super.hitTest() method also checks hitTestChildren(). We don't
// want that in this case because we've padded around the children per
// tapTargetSize.
if
(!
size
.
contains
(
position
))
{
return
false
;
}
// Only adjust one axis to ensure the correct button is tapped.
Offset
center
;
if
(
direction
==
Axis
.
horizontal
)
{
center
=
Offset
(
position
.
dx
,
child
!.
size
.
height
/
2
);
}
else
{
center
=
Offset
(
child
!.
size
.
width
/
2
,
position
.
dy
);
}
return
result
.
addWithRawTransform
(
transform:
MatrixUtils
.
forceToPoint
(
center
),
position:
center
,
hitTest:
(
BoxHitTestResult
result
,
Offset
position
)
{
assert
(
position
==
center
);
return
child
!.
hitTest
(
result
,
position:
center
);
},
);
}
}
packages/flutter/test/material/toggle_buttons_test.dart
View file @
a395c952
...
...
@@ -1591,6 +1591,96 @@ void main() {
},
);
testWidgets
(
'Tap target size is configurable by ThemeData.materialTapTargetSize'
,
(
WidgetTester
tester
)
async
{
Widget
buildFrame
(
MaterialTapTargetSize
tapTargetSize
,
Key
key
)
{
return
Theme
(
data:
ThemeData
(
materialTapTargetSize:
tapTargetSize
),
child:
Material
(
child:
boilerplate
(
child:
ToggleButtons
(
key:
key
,
constraints:
const
BoxConstraints
(
minWidth:
32.0
,
minHeight:
32.0
),
isSelected:
const
<
bool
>[
false
,
true
,
false
],
onPressed:
(
int
index
)
{},
children:
const
<
Widget
>[
Text
(
'First'
),
Text
(
'Second'
),
Text
(
'Third'
),
],
),
),
),
);
}
final
Key
key1
=
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
MaterialTapTargetSize
.
padded
,
key1
));
expect
(
tester
.
getSize
(
find
.
byKey
(
key1
)),
const
Size
(
228.0
,
48.0
));
final
Key
key2
=
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
MaterialTapTargetSize
.
shrinkWrap
,
key2
));
expect
(
tester
.
getSize
(
find
.
byKey
(
key2
)),
const
Size
(
228.0
,
34.0
));
});
testWidgets
(
'Tap target size is configurable'
,
(
WidgetTester
tester
)
async
{
Widget
buildFrame
(
MaterialTapTargetSize
tapTargetSize
,
Key
key
)
{
return
Material
(
child:
boilerplate
(
child:
ToggleButtons
(
key:
key
,
tapTargetSize:
tapTargetSize
,
constraints:
const
BoxConstraints
(
minWidth:
32.0
,
minHeight:
32.0
),
isSelected:
const
<
bool
>[
false
,
true
,
false
],
onPressed:
(
int
index
)
{},
children:
const
<
Widget
>[
Text
(
'First'
),
Text
(
'Second'
),
Text
(
'Third'
),
],
),
),
);
}
final
Key
key1
=
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
MaterialTapTargetSize
.
padded
,
key1
));
expect
(
tester
.
getSize
(
find
.
byKey
(
key1
)),
const
Size
(
228.0
,
48.0
));
final
Key
key2
=
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
MaterialTapTargetSize
.
shrinkWrap
,
key2
));
expect
(
tester
.
getSize
(
find
.
byKey
(
key2
)),
const
Size
(
228.0
,
34.0
));
});
testWidgets
(
'Tap target size is configurable for vertical axis'
,
(
WidgetTester
tester
)
async
{
Widget
buildFrame
(
MaterialTapTargetSize
tapTargetSize
,
Key
key
)
{
return
Material
(
child:
boilerplate
(
child:
ToggleButtons
(
key:
key
,
tapTargetSize:
tapTargetSize
,
constraints:
const
BoxConstraints
(
minWidth:
32.0
,
minHeight:
32.0
),
direction:
Axis
.
vertical
,
isSelected:
const
<
bool
>[
false
,
true
,
false
],
onPressed:
(
int
index
)
{},
children:
const
<
Widget
>[
Text
(
'1'
),
Text
(
'2'
),
Text
(
'3'
),
],
),
),
);
}
final
Key
key1
=
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
MaterialTapTargetSize
.
padded
,
key1
));
expect
(
tester
.
getSize
(
find
.
byKey
(
key1
)),
const
Size
(
48.0
,
100.0
));
final
Key
key2
=
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
MaterialTapTargetSize
.
shrinkWrap
,
key2
));
expect
(
tester
.
getSize
(
find
.
byKey
(
key2
)),
const
Size
(
34.0
,
100.0
));
});
// Regression test for https://github.com/flutter/flutter/issues/73725
testWidgets
(
'Border radius paint test when there is only one button'
,
(
WidgetTester
tester
)
async
{
final
ThemeData
theme
=
ThemeData
();
...
...
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