如何在Flutter中设计实现顶部矩形、底部半圆形的自定义按钮

Flutter 实现顶部矩形、底部半圆形按钮
实现方案
方案1:自定义ShapeBorder(推荐)
直接适配Flutter原生按钮的shape参数,按钮的水波纹、边框效果都会严格限制在自定义形状内,兼容性最好。
自定义形状类代码
import 'package:flutter/material.dart'; class TopRectBottomCircleBorder extends ShapeBorder { final BorderSide side; const TopRectBottomCircleBorder({ this.side = BorderSide.none, }); @override EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width); @override Path getInnerPath(Rect rect, {TextDirection? textDirection}) { return Path()..addPath(getOuterPath(rect, textDirection: textDirection), Offset.zero); } @override Path getOuterPath(Rect rect, {TextDirection? textDirection}) { final radius = rect.width / 2; Path path = Path(); path.moveTo(rect.left, rect.top); path.lineTo(rect.right, rect.top); path.lineTo(rect.right, rect.height - radius); path.arcToPoint( Offset(rect.left, rect.height - radius), radius: Radius.circular(radius), clockwise: false, ); path.lineTo(rect.left, rect.top); path.close(); return path; } @override void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) { if (side.style == BorderStyle.none) return; canvas.drawPath(getOuterPath(rect, textDirection: textDirection), side.toPaint()); } @override ShapeBorder scale(double t) { return TopRectBottomCircleBorder(side: side.scale(t)); } }
调用示例
ElevatedButton( onPressed: () { // 点击逻辑 }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, foregroundColor: Colors.white, // 固定宽高保证底部半圆比例正确 fixedSize: const Size(120, 140), // 应用自定义形状,如需边框可配置side参数 shape: const TopRectBottomCircleBorder( // side: BorderSide(color: Colors.black, width: 2), ), ), child: const Text("按钮"), )
方案2:ClipPath裁剪(轻量实现)
如果不需要自定义边框,可直接用ClipPath裁剪组件实现,代码更简洁。
实现代码
ClipPath( clipper: _BottomCircleClipper(), child: ElevatedButton( onPressed: () {}, style: ElevatedButton.styleFrom( fixedSize: const Size(120, 140), backgroundColor: Colors.blue, ), child: const Text("按钮"), ), ) class _BottomCircleClipper extends CustomClipper<Path> { @override Path getClip(Size size) { final radius = size.width / 2; Path path = Path(); path.moveTo(0, 0); path.lineTo(size.width, 0); path.lineTo(size.width, size.height - radius); path.arcToPoint(Offset(0, size.height - radius), radius: Radius.circular(radius), clockwise: false); path.close(); return path; } @override bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false; }
注意事项
- 按钮宽度需要固定,保证底部半圆的半径等于宽度的1/2,才会形成标准半圆形
- 两种方案都适配所有Flutter官方按钮组件,可直接替换
ElevatedButton为TextButton、OutlinedButton等使用
内容的提问来源于stack exchange,提问作者Shanto George
相关产品推荐
相关产品推荐

