Flutter——路徑裁剪

前言:

        咋一看,什麼是路徑裁剪,這是什麼鬼?路徑怎麼裁剪,請看下面示例圖片,是否是一目瞭然,左圖按照必定的路徑對紅色區域進行裁剪,最後變成右邊圖的樣子,有人說,這有什麼用,咱們先不急,先來完成下面這種效果,而後再進行其餘效果實現。bash



一:基本路徑裁剪

1,建立工程,main.dart代碼以下

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(),
    );
  }
}複製代碼

2,建立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

3,代碼分析

      裁剪功能歸功於ClipPath這個組件,你想裁剪哪一個區域就在哪一個區域外面包裹一層ClipPath。ClipPath有個路徑屬性clipper,它規定咱們按照什麼規則去裁剪,須要一個CustomerClipper對象。爲此,咱們建立了一個名爲LineClip的類繼承自CustomerClipper,來實現咱們本身的裁剪規則,咱們重寫了兩個方法,主要看getClip方法,該方法有個參數size,它表明咱們裁剪區域的大小,裁剪區域寬高分別爲size.with,size.height。less

      接下來咱們看方法內部,建立了Path對象,它就是咱們裁剪的路徑具體規則。你們都畫過圓吧,從起點到終點造成一個閉環。那麼咱們如何畫上圖所示效果呢?咱們把path對象想象成一個畫筆,把畫筆移動到(0.0, 0.0),開始畫線,因此使用lineTo()方法,方法參數就是第一條線的終點,而後下一條線的起點就是上一條線的終點,以此類推,最後經過方法close()結束咱們的路徑,表明咱們畫完了,是否是很好理解。ide


二:實現 '個人' 界面常見效果

效果圖:ui


1,直接上代碼,main.dart

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(),
    );
  }
}複製代碼

2,MyClipPath2.dart

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


1,直接上代碼,main.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: MyClipPath3(),
    );
  }
}複製代碼

2,MyClipPath3.dart

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;
  }
}
複製代碼

3,說明

裁剪規則在代碼註釋裏面很詳細,讀者能夠本身運行起來看看效果,而後修改裁剪規則看看有什麼效果。debug


四:結束語

裁剪規則多種多樣,這裏只列舉了簡單的三種,其餘的讀者能夠自行嘗試。code

案例中若有錯誤,煩請指正,不勝感激!cdn