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

2021-03-08 10:42 更新

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

剪裁Widget 作用
ClipOval 子組件為正方形時(shí)剪裁為內(nèi)貼圓形,為矩形時(shí),剪裁為內(nèi)貼橢圓
ClipRRect 將子組件剪裁為圓角矩形
ClipRect 剪裁子組件到實(shí)際占用的矩形大?。ㄒ绯霾糠旨舨茫?/td>

下面看一個(gè)例子:

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è)為原來(lái)寬度一半,另一半會(huì)溢出
                child: avatar,
              ),
              Text("你好世界", style: TextStyle(color: Colors.green),)
            ],
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ClipRect(//將溢出部分剪裁
                child: Align(
                  alignment: Alignment.topLeft,
                  widthFactor: .5,//寬度設(shè)為原來(lái)寬度一半
                  child: avatar,
                ),
              ),
              Text("你好世界",style: TextStyle(color: Colors.green))
            ],
          ),
        ],
      ),
    );
  }
}

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

圖5-24

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

#CustomClipper

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

首先,自定義一個(gè)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ū)域始終不會(huì)發(fā)生變化時(shí)應(yīng)該返回false,這樣就不會(huì)觸發(fā)重新剪裁,避免不必要的性能開(kāi)銷。如果剪裁區(qū)域會(huì)發(fā)生變化(比如在對(duì)剪裁區(qū)域執(zhí)行一個(gè)動(dòng)畫(huà)),那么變化后應(yīng)該返回true來(lái)重新執(zhí)行剪裁。

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

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)行的,所以不會(huì)影響組件的大小,這和Transform原理是相似的。

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)