咋一看,什么是路径裁剪,这是什么鬼?路径怎么裁剪,请看下面示例图片,是否是一目了然,左图按照必定的路径对红色区域进行裁剪,最后变成右边图的样子,有人说,这有什么用,咱们先不急,先来完成下面这种效果,而后再进行其余效果实现。bash
import 'package:flutter/material.dart';
import 'package:flutter_animation/animation/MyAnimation.dart';
import 'package:flutter_animation/clippath/MyClipPath.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyClipPath(),
);
}
}复制代码
import 'package:flutter/material.dart';
///create by:Administrator
///create at:2019-09-19 20:00
///des:
class MyClipPath extends StatefulWidget {
@override
_MyClipPathState createState() => _MyClipPathState();
}
class _MyClipPathState extends State<MyClipPath> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.blue,
child: Column(
children: <Widget>[
ClipPath(
clipper: LineClipOrign(),
child: Container(
width: double.infinity,
height: 300.0,
color: Colors.red,
),
),
],
),
),
);
}
}
class LineClip extends CustomClipper<Path>{
@override
Path getClip(Size size) {
var path = Path()
..moveTo(0.0, 0.0)
..lineTo(0.0, size.height)
..lineTo(size.width/2, size.height/2)
..lineTo(size.width, size.height)
..lineTo(size.width, 0.0)
..close();
return path;
}
//是否从新裁剪
@override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return true;
}
}复制代码
运行以后就是以上图片展现效果app
裁剪功能归功于ClipPath这个组件,你想裁剪哪一个区域就在哪一个区域外面包裹一层ClipPath。ClipPath有个路径属性clipper,它规定咱们按照什么规则去裁剪,须要一个CustomerClipper对象。为此,咱们建立了一个名为LineClip的类继承自CustomerClipper,来实现咱们本身的裁剪规则,咱们重写了两个方法,主要看getClip方法,该方法有个参数size,它表明咱们裁剪区域的大小,裁剪区域宽高分别为size.with,size.height。less
接下来咱们看方法内部,建立了Path对象,它就是咱们裁剪的路径具体规则。你们都画过圆吧,从起点到终点造成一个闭环。那么咱们如何画上图所示效果呢?咱们把path对象想象成一个画笔,把画笔移动到(0.0, 0.0),开始画线,因此使用lineTo()方法,方法参数就是第一条线的终点,而后下一条线的起点就是上一条线的终点,以此类推,最后经过方法close()结束咱们的路径,表明咱们画完了,是否是很好理解。ide
效果图:ui
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyClipPath2(),
);
}
}复制代码
import 'package:flutter/material.dart';
///create by:Administrator
///create at:2019-09-19 21:33
///des:
class MyClipPath2 extends StatefulWidget {
@override
_MyClipPath2State createState() => _MyClipPath2State();
}
class _MyClipPath2State extends State<MyClipPath2> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: ClipPath(
child: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
//渐变色
colors: [Colors.red, Colors.blue, Colors.amberAccent],
begin: Alignment.centerRight,
end: Alignment(-1.0, -1.0))),
),
Column(
children: [
Padding(
padding: EdgeInsets.only(top: 50.0),
child: Container(
width: 100.0,
height: 100.0,
decoration: new BoxDecoration(
border: Border.all(color: Colors.yellow, width: 1.0),
color: const Color(0xFFFFFFFF), // border color
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage("images/image2.jpeg"))))),
],
),
],
),
clipper: MyHeader(),
));
}
}
class MyHeader extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path()
..lineTo(0.0, size.height / 2 + 50)
..lineTo(size.width, size.height / 2 - 80)
..lineTo(size.width, 0)
..close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}
复制代码
效果图:spa
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyClipPath3(),
);
}
}复制代码
import 'package:flutter/material.dart';
///create by:Administrator
///create at:2019-09-19 21:33
///des:
class MyClipPath3 extends StatefulWidget {
@override
_MyClipPath3State createState() => _MyClipPath3State();
}
class _MyClipPath3State extends State<MyClipPath3> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: Column(
children: <Widget>[
ClipPath(
clipper: BottonClipper(),
child: Container(
width: double.infinity,
height: 300.0,
child: Stack(
fit: StackFit.expand,
children: [
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
//渐变色
colors: [Colors.red, Colors.blue, Colors.amberAccent],
begin: Alignment.centerRight,
end: Alignment(-1.0, -1.0))),
),
Column(
children: [
Padding(
padding: EdgeInsets.only(top: 50.0),
child: Container(
width: 100.0,
height: 100.0,
decoration: new BoxDecoration(
border: Border.all(color: Colors.yellow, width: 1.0),
shape: BoxShape.circle,
image: DecorationImage(
image: AssetImage("images/image2.jpeg"))))),
Padding(
padding: EdgeInsets.fromLTRB(0.0, 20, 0.0, 0.0),
child: Text("点我登陆",style: TextStyle(color: Colors.white,fontSize: 20.0),),
),
],
),
],
),
),
),
],
),
),
);
}
}
class BottonClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
// 路径
Path path = Path();
//曲度 值越大,曲线越陡峭
var curvature=50;
// 设置路径的开始点
path.lineTo(0, 0);
path.lineTo(0, size.height-curvature);
// 设置曲线的开始样式
var firstControlPoint = Offset(size.width / 2, size.height);
// 设置曲线的结束样式
var firstEndPont = Offset(size.width, size.height - curvature);
// 把设置的曲线添加到路径里面
path.quadraticBezierTo(firstControlPoint.dx, firstControlPoint.dy,
firstEndPont.dx, firstEndPont.dy);
// 设置路径的结束点
path.lineTo(size.width, size.height-curvature);
path.lineTo(size.width, 0);
// 返回路径
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return false;
}
}
复制代码
裁剪规则在代码注释里面很详细,读者能够本身运行起来看看效果,而后修改裁剪规则看看有什么效果。debug
裁剪规则多种多样,这里只列举了简单的三种,其余的读者能够自行尝试。code
案例中若有错误,烦请指正,不胜感激!cdn