一般公司美工的设计图中增加了许多曲线设计,比如个人页面,还有首页的一些页面,之前比较偷懒的方式是让美工同学做一个PNG的透明图片,然后外边放一个Container.但其内容如果本身就不是图片,只是容器,这种放入图片的做法会让包体变大。其实我们完全可以使用贝塞尔曲线进行切割。页面如下图这种:
实现方式是通过ClipPath路径裁切控件,ClipPath主要有两个属性:
- child :要切割的元素,可以是容器,图片等等;
- clipper : 切割的路径,这个要和CustomClipper对象配合使用;
CustomClipper裁切路径
ClipPath中指定clipper ,自定义继承 CustomClipper,重写getClip方法 ,返回裁切路径。
一个二阶的贝塞尔曲线是需要控制点和终点的,控制点就像一块磁铁,把直线吸引过去,形成一个完美的弧度,这个弧度就是贝塞尔曲线了。
class MyClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height - 80);//设置起点
path.quadraticBezierTo(
size.width / 2, //第二个点x坐标
size.height, //第二个点y坐标
size.width, //第三个点x坐标
size.height - 80);//第四个点y坐标
path.lineTo(size.width, 0);//设置终点
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return false;
}
}
class _MyHeaderState extends State<MyHeader> {
@override
Widget build(BuildContext context) {
return ClipPath(
clipper: MyClipper(),
child: Container(
padding: EdgeInsets.only(left: 40, top: 50, right: 20),
height: 350,
width: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Color(0xFF3383CD),
Color(0xFF11249F),
],
),
image: DecorationImage(
image: AssetImage("assets/images/virus.png"),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return InfoScreen();
},
),
);
},
child: SvgPicture.asset("assets/icons/menu.svg"),
),
SizedBox(height: 20),
Expanded(
child: Stack(
children: <Widget>[
Positioned(
top: (widget.offset < 0) ? 0 : widget.offset,
child: SvgPicture.asset(
widget.image,
width: 230,
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
),
),
Positioned(
top: 20 - widget.offset / 2,
left: 150,
child: Text(
"${widget.textTop} \n${widget.textBottom}",
style: kHeadingTextStyle.copyWith(
color: Colors.white,
),
),
),
Container(), // I dont know why it can't work without container
],
),
),
],
),
),
);
}
}
上面代码的基础上修改为波浪式的贝塞尔曲线,波浪形式的只要把裁切变成两个对称的贝塞尔曲线就可以实现了。
class MyClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, size.height - 80);
path.quadraticBezierTo(
size.width / 4, size.height,
size.width / 2, size.height -80,);
path.quadraticBezierTo(
size.width / 4 * 3, size.height - 160,
size.width, size.height - 80);
path.lineTo(size.width, 0);
path.close();
return path;
}