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

2021-03-08 10:42 更新

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

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

下面看一個例子:

  1. import 'package:flutter/material.dart';
  2. class ClipTestRoute extends StatelessWidget {
  3. @override
  4. Widget build(BuildContext context) {
  5. // 頭像
  6. Widget avatar = Image.asset("imgs/avatar.png", width: 60.0);
  7. return Center(
  8. child: Column(
  9. children: <Widget>[
  10. avatar, //不剪裁
  11. ClipOval(child: avatar), //剪裁為圓形
  12. ClipRRect( //剪裁為圓角矩形
  13. borderRadius: BorderRadius.circular(5.0),
  14. child: avatar,
  15. ),
  16. Row(
  17. mainAxisAlignment: MainAxisAlignment.center,
  18. children: <Widget>[
  19. Align(
  20. alignment: Alignment.topLeft,
  21. widthFactor: .5,//寬度設(shè)為原來寬度一半,另一半會溢出
  22. child: avatar,
  23. ),
  24. Text("你好世界", style: TextStyle(color: Colors.green),)
  25. ],
  26. ),
  27. Row(
  28. mainAxisAlignment: MainAxisAlignment.center,
  29. children: <Widget>[
  30. ClipRect(//將溢出部分剪裁
  31. child: Align(
  32. alignment: Alignment.topLeft,
  33. widthFactor: .5,//寬度設(shè)為原來寬度一半
  34. child: avatar,
  35. ),
  36. ),
  37. Text("你好世界",style: TextStyle(color: Colors.green))
  38. ],
  39. ),
  40. ],
  41. ),
  42. );
  43. }
  44. }

運(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

  1. class MyClipper extends CustomClipper<Rect> {
  2. @override
  3. Rect getClip(Size size) => Rect.fromLTWH(10.0, 15.0, 40.0, 30.0);
  4. @override
  5. bool shouldReclip(CustomClipper<Rect> oldClipper) => false;
  6. }

  • 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è)置一個紅色背景:

  1. DecoratedBox(
  2. decoration: BoxDecoration(
  3. color: Colors.red
  4. ),
  5. child: ClipRect(
  6. clipper: MyClipper(), //使用自定義的clipper
  7. child: avatar
  8. ),
  9. )

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

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

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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號