在我們實際的項目開發中,經常會遇到頁面UI內容過多,導致手機一屏展示不完的情況出現,以Android為例,在Android中遇到這類情況的做法通常就是使用ScrollView將內容包裹起來,如果不做可滑動的處理,Android上的表現為頁面的部分內容無法展示,而在Flutter中,如果內容過多無法展... ...
如需轉載,請註明出處:Flutter學習筆記(24)--SingleChildScrollView滾動組件
在我們實際的項目開發中,經常會遇到頁面UI內容過多,導致手機一屏展示不完的情況出現,以Android為例,在Android中遇到這類情況的做法通常就是使用ScrollView將內容包裹起來,如果不做可滑動的處理,Android上的表現為頁面的部分內容無法展示,而在Flutter中,如果內容過多無法展示完全,屏幕的邊界會給我們一個OVERFLOWED的警告提示,在Flutter中我們通常使用SingleChildScrollView處理滑動,這裡需要註意的是,通常SingleChildScrollView只應在期望的內容不會超過屏幕太多時使用,這是因為SingleChildScrollView不支持基於Sliver的延遲實例化模式,所以如果預計視口可能包含超出屏幕尺寸太多的內容時使用SingleChildScrollView將會導致性能差的問題,此時應該使用一些支持Sliver延遲載入的可滾動組件,如ListView。
基於Sliver的延遲構建模式:
通常可滾動組件的子組件可能會非常多,占用的總高度也會非常大,如果要一次性將子組件全部構建出將會導致性能差的問題出現,為此,Flutter中提出一個Sliver(中文為"薄片"的意思)概念,如果一個可滾動組件支持Sliver模型,那麼該滾動組件可以將子組件分成好多個薄片(Sliver),只有當Sliver出現在視口時才會去構建它,這種模型也成為"基於Sliver的延遲構建模型"。可滾動組件中有很多都支持基於Sliver的延遲構建模型,如ListView、GridView,但是也有不支持該模型的,如SingleChildScrollView
import 'package:flutter/material.dart'; void main() => runApp(DemoApp()); class DemoApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'SingleChildScrollView Demo', home: new Scaffold( appBar: AppBar( title: new Text('SingleChildScrollView Demo'), ), body: new Center( child: new Column( children: <Widget>[ Container( width: 300.0, height: 200.0, color: Colors.blue, ), Container( width: 300.0, height: 200.0, color: Colors.yellow, ), Container( width: 300.0, height: 200.0, color: Colors.pink, ), Container( width: 300.0, height: 200.0, color: Colors.blue, ), Container( width: 300.0, height: 200.0, color: Colors.yellow, ), Container( width: 300.0, height: 200.0, color: Colors.pink, ), Container( width: 300.0, height: 200.0, color: Colors.blue, ), ], ), ), ), ); } }
在Flutter實現頁面滑動需要用到SingleChildScrollView組件,SingleChildScrollView和Android中ScrollView類似,都是只能接收一個子組件,先看一下SingleChildScrollView的源碼:
const SingleChildScrollView({ Key key, //滾動方向,預設是垂直方向 this.scrollDirection = Axis.vertical, //是否按照閱讀方向相反的方向滑動 this.reverse = false, //內容邊距 this.padding, //是否使用widget樹中預設的PrimaryScrollController bool primary, //此屬性接受一個ScrollPhysics類型的對象,它決定可以滾動如何響應用戶操作,比如用戶滑動完抬起手指後,繼續執行動畫,或者滑動到邊界時,如何顯示。 //預設情況下,Flutter會根據具體平臺分別使用不同的ScrollPhysics對象,對應不同的顯示效果,如當滑動到邊界時,繼續拖動的話,在iOS上會出現彈性效果, //而在Android上會出現微光效果。如果你想在所有平臺下使用同一種效果,可以顯示指定一個固定的ScrollPhysics。 //Flutter SDK包含兩個ScrollPhysics的子類。1.ClampingScrollPhysics:Android下微光效果,2.BouncingScrollPhysics:iOS下彈性效果 this.physics, //此屬性接收一個ScrollController對象,ScrollController的主要作用是控制滾動位置和監聽滾動事件。 //預設情況下,Widget樹中會有一個預設的PrimaryScrollController,如果子樹中的可滾動組件沒有顯示的指定controller,並且primary屬性值為true時,可滾動組件會使用這個預設的ScrollController。 //這種機制帶來的好處是父組件可以控制子樹中可滾動的滾動行為,例:scaffold正是使用這種機制在iOS中實現了點擊導航回到頂部的功能。 this.controller, this.child, })
Demo示例:
import 'package:flutter/material.dart'; void main() => runApp(DemoApp()); class DemoApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'SingleChildScrollView Demo', home: new Scaffold( appBar: AppBar( title: new Text('SingleChildScrollView Demo'), ), body: new SingleChildScrollView( physics: BouncingScrollPhysics(), child: new Center( child: new Column( children: <Widget>[ Container( width: 300.0, height: 200.0, color: Colors.blue, ), Container( width: 300.0, height: 200.0, color: Colors.yellow, ), Container( width: 300.0, height: 200.0, color: Colors.pink, ), Container( width: 300.0, height: 200.0, color: Colors.blue, ), Container( width: 300.0, height: 200.0, color: Colors.yellow, ), Container( width: 300.0, height: 200.0, color: Colors.pink, ), Container( width: 300.0, height: 200.0, color: Colors.blue, ), ], ), ), ), ), ); } }
效果截圖: