前言:
這是我參與8月更文挑戰的第 13 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
一、認識 Visibility 元件
前面介紹了 Offstage 元件可以控制 child
的顯隱
,與它相比較的往往是 Visibility
元件。Offstage 原始碼中有對 Visibility
的一句介紹:它可以更高效地隱藏
元件(儘管不那麼微妙)。
現在仔細想想,Opacity
、Offstage
和 Visibility
都可以控制元件的顯示/隱藏
。那它們之間有什麼樣的區別和聯絡呢?通過本文,我將從 Visibility
原始碼中為你揭曉答案。
1.Visibility 基本資訊
下面是 Visibility
元件類的定義
和 構造方法
,可以看出它繼承自 StatelessWidget
。例項化時必須傳入和 child
元件,另外還有一堆選填的 bool
屬性和一個 replacement
元件。
2.Visibility 的簡單使用
下面是 Visibility
元件的預設效果,中間的圖示是待顯隱
元件,通過點選按鈕切換現有狀態。可以看出,直接使用 Visibility
時,元件隱藏時不會佔位
。
class OffstageDemo extends StatefulWidget {
@override
_OffstageDemoState createState() => _OffstageDemoState();
}
class _OffstageDemoState extends State<OffstageDemo> {
bool _visible = true;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
child: const Text('切換顯隱'),
onPressed: _toggleVisible,
),
Visibility(
visible: _visible,
child: buildChild(),
),
Text('預設情況'),
],
);
}
void _toggleVisible() {
setState(() {
_visible = !_visible;
});
}
Widget buildChild() => const Padding(
padding: const EdgeInsets.all(10),
child: Icon(
Icons.camera_outlined,
color: Colors.green,
size: 50,
),
);
}
複製程式碼
3.Visibility 的佔位元件
Visibility
中有一個 replacement
的可選屬性,型別是 Widget
,用於佔位。
this.replacement = const SizedBox.shrink(),
final Widget replacement;
複製程式碼
預設 replacement
是 SizedBox.shrink()
,即寬高為 0
的 SizedBox
。
我們可以通過 Flutter Inspector
檢視樹的詳細資訊,可以看出在隱藏時。渲染樹中確實有通過 SizedBox
物件的渲染物件節點,且寬高為 0 。
下面是設定 replacement
的效果,可以看出在隱藏時,會顯示 replacement
對應的元件。
Visibility(
visible: _visible,
child: buildChild(),
replacement: buildPlaceholder(),
),
Widget buildPlaceholder() => Container(
width: 50,
height: 50,
padding: const EdgeInsets.all(10),
child: Placeholder(),
);
複製程式碼
4. 五個 maintainXXX
下面就剩下來五個 maintainXXX
的布林屬性。
我們先來看一下,構造中的斷言處理:
先看一下 maintainSize
,表示隱藏時是否保持尺寸。預設為 false
。通過斷言 2 可以看出:
maintainSize: true 時,必須 maintainAnimation: true ,否則斷言失敗。
複製程式碼
通過斷言 1 可以看出:
maintainAnimation: true 時,必須 maintainState: true ,否則斷言失敗。
複製程式碼
也就是說,如果想要保持尺寸,必須 maintainAnimation
和 maintainState
。如下是 maintainSize
的效果,這樣隱藏時,原尺寸區域不會消失。
Visibility(
visible: _visible,
child: buildChild(),
maintainSize: true,
maintainAnimation: true,
maintainState: true,
),
複製程式碼
看一下結構,有一個透明度為 0
的 Opacity
元件,看懂的應該能會心一笑。
maintainInteractivity
的作用也非常簡單,它可以控制在隱藏時是否響應事件。
另外 maintainAnimation
和 maintainState
作用是什麼,就讓原始碼來告訴你吧。
二、 Visibility 的原始碼實現
1. 尺寸和點選事件的保持
Visibility
元件作為一個 StatelessWidget
,就決定它本身並不掌握"核心科技"
,只是在 build
方法中組合使用其他元件而已。在原始碼 build
方法中,可以看出:
如果 maintainSize
為 true
,會通過 Opacity
元件進行包裹,根據 visible
控制透明度。 maintainInteractivity
為 false
, 會通過 IgnorePointer
元件進行包裹,忽略點選事件。
2. 保持狀態和動畫
如果 maintainState
為 true
,會通過 Offstage
元件進行包裹,根據 visible
控制是否顯示,對於 Offstage 元件介紹,詳見此文。如果 maintainAnimation
為 false
, 會通過 TickerMode
元件進行包裹,在隱藏時禁用子元件動畫。 TickerMode 元件介紹,詳見此文
3.為什麼說 Visibility
是高效的?
如果五個 maintainXXX
是預設情況,那麼 Visibility
元件直接通過 visible
屬性決定返回元件,不需要通過 Opacity
或 Offstage
元件完成顯隱功能。 另外,maintainState
和 maintainAnimation
必須同時為 true
,這也能給使用者一個保障,避免使用 Offstage
是忘記子元件禁止動畫。
到這裡可以看出,Visibility 元件
可以說是顯隱功能的合集。能控制四個屬性:是否接受事件
、是否保持尺寸
、是否保持狀態
、是否停止動畫
,分別由 IgnorePointer
、Opacity
、Offstage
和 TickerMode
實現。是一個上層的簡單封裝,目的是方便使用者使用,儘可能少犯錯誤。所以如果想顯隱元件,又不知道用什麼好,Visibility
可以無腦翻牌。
那Visibility
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~