效果图
一般实现方式
- ClipPath
- CustomClipper
贝塞尔曲线
/// 一般的方式
class OldMyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ClipRRect Demo")),
body: Center(
// 这里使用 ClipPath
child: ClipPath(
clipper:ClipperPath(),
child: Container(
width: 400,
height: 200,
color: Colors.blue,
alignment: Alignment.center,
child: Text(
'Flutter\n\nClipRRect',
textAlign: TextAlign.center,
),
),
),
),
);
}
}
/// 创建剪裁路径
class ClipperPath extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0.0, size.height - 50);
var firstControlPoint = Offset(size.width / 4, size.height);
var firstPoint = Offset(size.width / 2, size.height);
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
firstPoint.dx, firstPoint.dy);
var secondControlPoint = Offset(size.width - (size.width / 4), size.height);
var secondPoint = Offset(size.width, size.height - 50);
path.quadraticBezierTo(secondControlPoint.dx, secondControlPoint.dy,
secondPoint.dx, secondPoint.dy);
path.lineTo(size.width, 0.0);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
效果
简单的实现方式
ClipRRect
- BorderRadius ```dart
class MyWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(“ClipRRect Demo”)), body: Center( /// 这里使用 ClipRRect child: ClipRRect( /// 设置剪裁半径 /// 顶部是 10 圆形 /// 底部是 x:200 和 y:50 半径的椭圆 borderRadius: BorderRadius.vertical( top: Radius.circular(10), bottom: Radius.elliptical(200, 50), ), child: Container( width: 400, height: 200, color: Colors.blue, alignment: Alignment.center, child: Text( ‘Flutter\n\nClipRRect’, textAlign: TextAlign.center, ), ), ), ), ); } } ```
效果
在线查看效果
- https://dartpad.cn/6cc7f861940123eb0ffa3ab19e3349b0?null_safety=true
总结
虽然两种方式都可以实现想要的效果,但是从代码量上有非常大的差别,后者清晰明了,不用过多的封装,前者控制点自由,样式可以更多,但是需要编写许多的计算逻辑和封装才可以。
语雀内容