Flutter實(shí)戰(zhàn) 剪裁(Clip)

2021-03-08 10:42 更新

Flutter 中提供了一些剪裁函數(shù),用于對組件進(jìn)行剪裁。

剪裁Widget 作用
ClipOval 子組件為正方形時剪裁為內(nèi)貼圓形,為矩形時,剪裁為內(nèi)貼橢圓
ClipRRect 將子組件剪裁為圓角矩形
ClipRect 剪裁子組件到實(shí)際占用的矩形大小(溢出部分剪裁)

下面看一個例子:

import 'package:flutter/material.dart';


class ClipTestRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 頭像  
    Widget avatar = Image.asset("imgs/avatar.png", width: 60.0);
    return Center(
      child: Column(
        children: <Widget>[
          avatar, //不剪裁
          ClipOval(child: avatar), //剪裁為圓形
          ClipRRect( //剪裁為圓角矩形
            borderRadius: BorderRadius.circular(5.0),
            child: avatar,
          ), 
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Align(
                alignment: Alignment.topLeft,
                widthFactor: .5,//寬度設(shè)為原來寬度一半,另一半會溢出
                child: avatar,
              ),
              Text("你好世界", style: TextStyle(color: Colors.green),)
            ],
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ClipRect(//將溢出部分剪裁
                child: Align(
                  alignment: Alignment.topLeft,
                  widthFactor: .5,//寬度設(shè)為原來寬度一半
                  child: avatar,
                ),
              ),
              Text("你好世界",style: TextStyle(color: Colors.green))
            ],
          ),
        ],
      ),
    );
  }
}

運(yùn)行效果如圖5-24所示:

圖5-24

上面示例代碼注釋比較詳細(xì),在此不再贅述。但值得一提的是最后的兩個Row!它們通過Align設(shè)置widthFactor為0.5后,圖片的實(shí)際寬度等于 60×0.5,即原寬度一半,但此時圖片溢出部分依然會顯示,所以第一個“你好世界”會和圖片的另一部分重合,為了剪裁掉溢出部分,我們在第二個Row中通過ClipRect將溢出部分剪裁掉了。

#CustomClipper

如果我們想剪裁子組件的特定區(qū)域,比如,在上面示例的圖片中,如果我們只想截取圖片中部40×30像素的范圍應(yīng)該怎么做?這時我們可以使用CustomClipper來自定義剪裁區(qū)域,實(shí)現(xiàn)代碼如下:

首先,自定義一個CustomClipper

class MyClipper extends CustomClipper<Rect> {
  @override
  Rect getClip(Size size) => Rect.fromLTWH(10.0, 15.0, 40.0, 30.0);


  @override
  bool shouldReclip(CustomClipper<Rect> oldClipper) => false;
}

  • getClip()是用于獲取剪裁區(qū)域的接口,由于圖片大小是60×60,我們返回剪裁區(qū)域?yàn)?code>Rect.fromLTWH(10.0, 15.0, 40.0, 30.0),即圖片中部40×30像素的范圍。
  • shouldReclip() 接口決定是否重新剪裁。如果在應(yīng)用中,剪裁區(qū)域始終不會發(fā)生變化時應(yīng)該返回false,這樣就不會觸發(fā)重新剪裁,避免不必要的性能開銷。如果剪裁區(qū)域會發(fā)生變化(比如在對剪裁區(qū)域執(zhí)行一個動畫),那么變化后應(yīng)該返回true來重新執(zhí)行剪裁。

然后,我們通過ClipRect來執(zhí)行剪裁,為了看清圖片實(shí)際所占用的位置,我們設(shè)置一個紅色背景:

DecoratedBox(
  decoration: BoxDecoration(
    color: Colors.red
  ),
  child: ClipRect(
      clipper: MyClipper(), //使用自定義的clipper
      child: avatar
  ),
)

運(yùn)行效果如圖5-25所示:

可以看到我們的剪裁成功了,但是圖片所占用的空間大小仍然是60×60(紅色區(qū)域),這是因?yàn)榧舨檬窃?layout 完成后的繪制階段進(jìn)行的,所以不會影響組件的大小,這和Transform原理是相似的。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號