[Flutter翻譯]Flutter中的剪下

Sunbreak發表於2020-07-23

原文地址:medium.com/flutter-com…

原文作者:medium.com/@rahiche

釋出時間:2018年10月9日 - 閱讀6分鐘

[Flutter翻譯]Flutter中的剪下

在計算機圖形學中,將渲染限制在某一特定區域的行為被稱為 "剪下"。剪輯區域被提供給畫布,這樣渲染引擎將只 "繪製 "定義區域內的畫素。在該區域外 "繪製 "的任何東西都不會被渲染。

作為開發者,我們使用剪接來建立具有特殊效果的、看起來很棒的、自定義的使用者介面。正如標題所說,這裡我們將討論如何在Flutter中進行剪下,讓你在短時間內建立令人瞠目結舌的?介面。

入門

讓我們從建立一個赤裸裸的應用程式開始,在Scaffold的中心建立一個簡單的200x200的紅色矩形。

import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(
      home: MyApp(),
    ));

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Container(
          color: Colors.red,
          width: 200.0,
          height: 200.0,
        ),
      ),
    );
  }
}
複製程式碼

定製剪下

CustomClipper是Flutter中剪裁的基礎類,它被四個小部件使用。ClipRect , ClipRRect, ClipOval, ClipPath

每一個都有一個定義的行為,所以如果你在ClipOval中包裹一個紅色Container,結果是一個圓形。

[Flutter翻譯]Flutter中的剪下

改變Container的高度或寬度,它就會變成一個橢圓形。想想看,在Flutter中調整這樣的橢圓是多麼的快速和容易;您所要做的就是改變高度和/或寬度,並按Ctrl+\為熱重新載入,看看您的變化在不到一秒鐘的時間裡是如何的。大一點,寬一點,不也許小一點......

[Flutter翻譯]Flutter中的剪下

現在,如果你想自定義剪輯的大小和位置,這就是CustomClipper的作用。讓我們為我們的ClipOval Widget建立一個吧

class CustomRect extends CustomClipper<Rect>{
  @override
  Rect getClip(Size size) {
    // TODO: implement getClip
  }
  @override
  bool shouldReclip(CustomRect oldClipper) {
    // TODO: implement shouldReclip
  }
}
複製程式碼

注意:在類的繼承部分,對通用型別進行具體說明是非常重要的,你可以從 clipper 屬性中看到你的 widget 需要什麼。在這個例子中是Rect

當你從CustomClipper類繼承時,你需要覆蓋兩個方法。

第一個是getClip()。這為你提供了被剪下的RenderBox的大小,並要求你返回一個Rect。這個Rect將定義剪輯的大小和位置。順便說一下:每個可見的Widget都有一個RenderBox)。

所以,如果我們返回這個:

Rect getClip(Size size) {
  Rect rect = Rect.fromLTRB(0.0, 0.0, size.width, size.height);
  return rect;
}
複製程式碼

程式碼說明:使用fromLTRB建構函式,我們必須提供左、上、右、下的點。

這不會有任何改變,因為這裡的 Rect 和 widget 的邊界框是一樣的。

[Flutter翻譯]Flutter中的剪下

但是如果你想只顯示橢圓的一半呢?我們可以很容易做到,將矩形的左點改為-size.width,如果想看另一半,只需將右點改為size.width*2即可。

[Flutter翻譯]Flutter中的剪下

你需要覆蓋的另一個方法是shouldReclip()。每當你提供一個新的物件(在本例中是CustomClipper<Rect>)被建立時,這個方法就會被呼叫,以與舊的物件進行比較,當它返回true時,getClip就會被呼叫,而不是反過來,因為當盒子的大小改變時,getClip方法也會被觸發。

快速注意:測試時要確保shouldReclip返回true。如果沒有,請明確地設定它,這樣Hot Reload就會正確地改變剪輯區域。

各種剪下Widget

到目前為止,我們只介紹了一般的剪下,並舉了使用ClipOval的例子。現在讓我們來談談其他的剪裁部件,看看每個部件提供了什麼。

ClipRect

用來從一個較大的影像中剪出一個矩形區域。例如,如果你只想要較大影像中的一小塊矩形區域,你可以使用ClipRect。

[Flutter翻譯]Flutter中的剪下

Container(
  child: Align(
    alignment: Alignment.bottomRight,
    heightFactor: 0.5,
    widthFactor: 0.5,
    child: Image.network(
      "https://static.vinepair.com/wp-content/uploads/2017/03/darts-int.jpg"),
  ),
),
複製程式碼

ClipRRect

這和ClipRect一樣,都是圓角。請注意,你可以為每個角設定不同的曲率,而不是強迫你讓四個角的半徑都一樣。在這個例子中,只有三個角被賦予了數值。我們要做的就是讓左下角保持 "正方形",並且不給它分配任何值。預設情況下它是正方形的。

[Flutter翻譯]Flutter中的剪下

ClipRRect(
  borderRadius: BorderRadius.only(
    topLeft: Radius.circular(25.0),
    topRight: Radius.circular(25.0),
    bottomRight: Radius.circular(25.0),
  ),
  child: Align(
    alignment: Alignment.bottomRight,
    heightFactor: 0.5,
    widthFactor: 0.5,
    child: Image.network(
      "https://static.vinepair.com/wp-content/uploads/2017/03/darts-int.jpg"),
  ),
)
複製程式碼

ClipPath

用來使用路徑夾住一個自定義區域。如果你能用ClipRectClipRRectClipOval實現你想要的東西,那麼你真的想用它們來代替。但是當你需要的時候,ClipPath可以成為你的救星。

比方說,你想剪輯一個三角形。

[Flutter翻譯]Flutter中的剪下

class TriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(size.width, 0.0);
    path.lineTo(size.width / 2, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(TriangleClipper oldClipper) => false;
}
複製程式碼

clipBehavior

clipBehavior屬性是新的,你會在Material Widgets中看到很多,因為幾個月前討論的突破性變化。有了這個變化,Flutter應用程式的速度快了30%,但這個突破性的變化的一部分是它禁用了對saveLayer的自動呼叫,它暴露了一個clipBehavior屬性。有了它,你可以設定如何剪輯widget內容。大多數小元件的預設行為是Clip.none

Clip.hardEdge

[Flutter翻譯]Flutter中的剪下

Clip.antiAlias

[Flutter翻譯]Flutter中的剪下

Clip.antiAliasWithSaveLayer.

[Flutter翻譯]Flutter中的剪下

正如你所看到的,antiAliasWithSaveLayerantiAlias之間沒有明顯的區別,但是和hardEdge有明顯的區別。在效能方面,它們之間有很大的區別,最快的是hardEdge,而antiAliasWithSaveLayer是最慢的。

渲染

在構建圖層樹的過程中,所有的剪下部件都會在PaintingContext中應用它們的剪下區域。當GPU將結果內容繪製到幀緩衝區時,我們新增的每一個圖層都會增加其複雜性。我們總是建議儘量減少剪裁,因為這會給GPU增加每個圖層的模板緩衝區,這樣會增加很多渲染時間。最好將剪裁控制在需要的範圍內,我們需要注意在動畫製作過程中儘量少用。如果你想知道的話,那麼請看Adam Barth在2016年介紹的Flutter的渲染管道

結束語

與其他框架相比,Flutter的速度非常快,但這部分是因為Flutter團隊提供了一個很好的API,它可以幫助你建立快速的應用程式;但有時會限制你使用會減慢你的應用程式速度的東西。正如Ian "Hixie" Hickson所說。

"我同意,做正確的剪裁是昂貴的。因此,我認為我們應該考慮是否可以重新設計框架,以完全避免剪接,除非明確要求。"

github.com/flutter/flu…

所以要記住費用,只有在真正需要的時候才使用剪裁,儘可能的使用優化後的小部件。

對我來說就是這樣! 我希望你喜歡我的第一篇英文文章。我通過給幾個編輯送百事可樂和多力多滋來賄賂他們,所以希望它能得到回報!


通過www.DeepL.com/Translator(免費版)翻譯

相關文章