Repository navigation
Support for MaterialTapTargetSize within ToggleButtons - #93259
Conversation
| switch (resolvedTapTargetSize) { | ||
| case MaterialTapTargetSize.padded: | ||
| return ConstrainedBox( | ||
| constraints: const BoxConstraints(), |
There was a problem hiding this comment.
This was necessary for some reason. @HansMuller thoughts?
There was a problem hiding this comment.
I'm not sure. The implication is that the _InputPadding class is not respecting its incoming constraints, so adding this class forces that to happen.
| switch (resolvedTapTargetSize) { | ||
| case MaterialTapTargetSize.padded: | ||
| return ConstrainedBox( | ||
| constraints: const BoxConstraints(), |
There was a problem hiding this comment.
I'm not sure. The implication is that the _InputPadding class is not respecting its incoming constraints, so adding this class forces that to happen.
|
I removed the case MaterialTapTargetSize.padded:
return _InputPadding(
minSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension),
direction: direction,
child: result,
);The demo below, which defines the height of the ToggleButtons with its constraints parameter, seems to work as expected. Working Demoimport 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({ Key? key }) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final List<bool> isSelected = <bool>[false, false, false];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ToggleButtons(
constraints: BoxConstraints(minWidth: 48.0, minHeight: 32.0),
tapTargetSize: MaterialTapTargetSize.padded,
isSelected: isSelected,
onPressed: (int index) {
setState(() {
isSelected[index] = !isSelected[index];
});
},
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.call),
Icon(Icons.cake),
],
),
),
);
}
}
void main() {
runApp(const MaterialApp(home: Home()));
}A version of the demo that constrains the height SizedBox to be 32 using a SizedBox above the ToggleButtons does fail, but that's to be expected, since the ToggleButtons widget has to respect to the incoming constraints. This happens with or without the extra BoxConstraints widget. Failing Demoimport 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({ Key? key }) : super(key: key);
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final List<bool> isSelected = <bool>[false, false, false];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SizedBox(
height: 32,
child: ToggleButtons(
tapTargetSize: MaterialTapTargetSize.padded,
isSelected: isSelected,
onPressed: (int index) {
setState(() {
isSelected[index] = !isSelected[index];
});
},
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.call),
Icon(Icons.cake),
],
),
),
),
);
}
}
void main() {
runApp(const MaterialApp(home: Home()));
}What's the test case that caused you to add the extra BoxConstraints widget? |
|
Hmm when I tried just removing the constrained box, the demo you defined still allowed the buttons to be tapped even when tapping way outside the bounds (see attached video). I'm tapping way above/below the widget and still triggered the buttons. Screen.Recording.2021-11-18.at.8.48.59.AM.mov |
|
Sorry, I didn't realize that was the problem we were trying to resolve. Will investigate further. |
|
The problem with the original version of the code was that @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);
},
);
} |
Ah that worked, thanks! |
guidezpl
left a comment
There was a problem hiding this comment.
_ ___ _____ __ __
| | / __|_ _| \/ |
| |_| (_ | | | | |\/| |
|____\___| |_| |_| |_|
| /// If the [tapTargetSize] is larger than [constraints], the buttons will | ||
| /// include a transparent margin that responds to taps. | ||
| /// | ||
| /// Always defaults to [ThemeData.materialTapTargetSize]. |
There was a problem hiding this comment.
| /// Always defaults to [ThemeData.materialTapTargetSize]. | |
| /// Defaults to [ThemeData.materialTapTargetSize]. |
|
|
||
| /// A widget to pad the area around a [ToggleButtons]'s children. | ||
| /// | ||
| /// This widget is based on a similar one using in [ButtonStyleButton] but it |
There was a problem hiding this comment.
there's an issue with this sentence. Overall I don't understand this comment. What does "tap target" in quotes mean? Which widget does "size of the widget" refer to?
There was a problem hiding this comment.
Reworded the sentence, hopefully thats better.
There was a problem hiding this comment.
| /// This widget is based on a similar one using in [ButtonStyleButton] but it | |
| /// This widget is based on a similar one used in [ButtonStyleButton] but it |
HansMuller
left a comment
There was a problem hiding this comment.
LGTM with a few small tweaks
| }) : super(key: key, child: child); | ||
|
|
||
| final Size minSize; | ||
|
|
|
|
||
| @override | ||
| void updateRenderObject(BuildContext context, covariant _RenderInputPadding renderObject) { | ||
| renderObject.minSize = minSize; |
|
|
||
| /// A widget to pad the area around a [ToggleButtons]'s children. | ||
| /// | ||
| /// This widget is based on a similar one using in [ButtonStyleButton] but it |
This change adds a MaterialTapTargetSize param to the ToggleButtons widget (and also hooks into the ThemeData.materialTapTargetSize property) so that ToggleButtons can benefit from the same behavior as regular buttons (standard tap target size while being visibly smaller on screen).
Fixes #93249
Screen.Recording.2021-11-08.at.11.56.27.AM.mov
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.