I want make 2 (elevated) buttons, one (backwards) L-shaped, and one a regular rounded text, like this:
So far I can think of 3 approaches, but not sure how to implement any of them:
clip
to clip out the inside of the L button, but I’m not sure how to get the rounded corners on the upper left portions correct; also I’m not sure how to ensure that the hit testing works right so the square button can actually be pressed.Stack
or something to make them into one Widget, but then how do I make that Stack
act like a single button?CustomPaint
, which seems hard to get all the curves right, especially as the buttons need to be dynamically sized, and then also I’d have to re-implement the logic of ElevatedButton
to make it pressable, focusable, etc.How would you lay out two buttons like this?
You can combine Stack and ShapeBorder for L button.
class LShapeBorder extends OutlinedBorder {
@override
OutlinedBorder copyWith({BorderSide? side}) => this;
@override
ui.Path getInnerPath(ui.Rect rect, {ui.TextDirection? textDirection}) =>
getOuterPath(rect, textDirection: textDirection);
@override
ui.Path getOuterPath(ui.Rect rect, {ui.TextDirection? textDirection}) {
// L shape
final Path path = Path();
final btnW = rect.width / 2 - 10;
// path.moveTo(rect.right - btnW, rect.top);
path.addRRect(
RRect.fromRectAndRadius(
Rect.fromLTRB(rect.right - btnW, rect.top, rect.right, rect.bottom),
const Radius.circular(8),
),
);
path.addRRect(
RRect.fromRectAndRadius(
Rect.fromLTRB(rect.left, rect.bottom - btnW, rect.right, rect.bottom),
const Radius.circular(8),
),
);
path.close();
return path;
}
@override
void paint(ui.Canvas canvas, ui.Rect rect,
{ui.TextDirection? textDirection}) {}
@override
ShapeBorder scale(double t) => this;
}
And usecase
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
height: 200,
width: 200,
child: Stack(
children: [
Align(
alignment: Alignment.topLeft,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
fixedSize: Size.square(100),
backgroundColor: Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
)),
onPressed: () {
debugPrint('1');
},
child: SizedBox(),
),
),
Positioned.fill(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
shape: LShapeBorder(),
),
onPressed: () {
debugPrint('2');
},
child: SizedBox(),
),
)
],
),
),
),
),
);
}
}