如何在Flutter中创建L形ElevatedButton及嵌套常规圆角按钮?
常规圆角按钮
这个实现非常直接,利用ElevatedButton原生的shape参数配置圆角即可:
ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), // 自定义圆角大小 ), padding: EdgeInsets.symmetric(horizontal: 40, vertical: 16), ), child: Text("常规圆角按钮"), )
反向L形按钮(最优实现)
推荐通过**自定义ShapeBorder**实现,既保留ElevatedButton原生的按压、聚焦、阴影等交互逻辑,又能精准控制按钮形状和点击区域,完美解决你提到的三个思路的痛点:
1. 自定义L形边框
创建继承自OutlinedBorder的自定义边框类,处理反向L形的路径和圆角逻辑:
import 'dart:math'; import 'package:flutter/material.dart'; class ReverseLShapeBorder extends OutlinedBorder { final double borderRadius; final double notchSize; // L形缺口的边长 const ReverseLShapeBorder({ this.borderRadius = 8.0, this.notchSize = 40.0, super.side, }); @override ReverseLShapeBorder copyWith({ BorderSide? side, double? borderRadius, double? notchSize, }) { return ReverseLShapeBorder( side: side ?? this.side, borderRadius: borderRadius ?? this.borderRadius, notchSize: notchSize ?? this.notchSize, ); } @override Path getInnerPath(Rect rect, {TextDirection? textDirection}) { return _getButtonPath(rect, isInner: true); } @override Path getOuterPath(Rect rect, {TextDirection? textDirection}) { return _getButtonPath(rect, isInner: false); } Path _getButtonPath(Rect rect, {required bool isInner}) { final adjust = isInner ? side.width / 2 : 0; final cornerRadius = Radius.circular(borderRadius - adjust); // 定义左上角缺口区域 final notchRect = Rect.fromLTWH( rect.left + adjust, rect.top + adjust, notchSize - adjust * 2, notchSize - adjust * 2, ); final path = Path() // 右下角圆角 ..moveTo(rect.right - adjust, rect.bottom - adjust) ..arcToPoint( Offset(rect.right - adjust, rect.top + adjust), radius: cornerRadius, clockwise: false, ) // 顶部边缘到缺口右侧 ..lineTo(notchRect.right, rect.top + adjust) // 缺口右上角圆角 ..arcToPoint( Offset(notchRect.right, notchRect.bottom), radius: cornerRadius, clockwise: false, ) // 缺口底部边缘到左侧 ..lineTo(rect.left + adjust, notchRect.bottom) // 左下角圆角 ..arcToPoint( Offset(rect.left + adjust, rect.bottom - adjust), radius: cornerRadius, clockwise: false, ) // 闭合路径 ..close(); return path; } @override void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { if (side.style == BorderStyle.none) return; final path = getOuterPath(rect, textDirection: textDirection); canvas.drawPath(path, side.toPaint()); } @override EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width); @override ShapeBorder scale(double t) { return ReverseLShapeBorder( side: side.scale(t), borderRadius: borderRadius * t, notchSize: notchSize * t, ); } }
2. 使用自定义边框创建L形按钮
将自定义边框传给ElevatedButton的shape参数,内部用Stack放置水平和垂直文本:
ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( shape: const ReverseLShapeBorder( borderRadius: 12.0, notchSize: 50.0, // 调整缺口大小 ), padding: EdgeInsets.zero, // 取消默认padding,自定义内部布局 minimumSize: Size(150, 150), // 按钮基础尺寸 ), child: Stack( children: [ // 水平文本(避开左上角缺口) Positioned( left: 60, // 比notchSize大一点,避免文本被缺口遮挡 top: 0, bottom: 0, child: Center( child: Text( "水平文本", style: TextStyle(fontSize: 16), ), ), ), // 垂直文本(旋转90度,避开缺口) Positioned( left: 0, top: 60, right: 0, child: Center( child: Transform.rotate( angle: -pi / 2, // 逆时针旋转90度 child: Text( "垂直文本", style: TextStyle(fontSize: 16), ), ), ), ), ], ), )
方案优势
- 完全复用
ElevatedButton原生交互:无需自己处理按压阴影、聚焦状态等逻辑 - 点击区域精准匹配L形:自定义
ShapeBorder会自动参与点击测试,缺口区域不会触发按钮点击 - 动态适配灵活:通过
notchSize和borderRadius参数可快速调整按钮形状,适配不同尺寸需求
内容的提问来源于stack exchange,提问作者bwk
相关产品推荐
相关产品推荐

