Flutter 頁面滾動吸頂詳解(NestedScrollView)

淺夏晴空發表於2021-11-19

前言

在業務開發中我們經常會有滾動吸頂的效果,目前Flutter也有很多種實現方式,這裡介紹一下本人在開發中使用到的基於NestedScrollView實現的滾動吸頂元件;以及中間涉及的各種定位的佈局操作;

效果

3AA6C32F47694FA7CE40FEC465D20071

NestedScrollView

首先了解一下NestedScrollView滾動元件;

NestedScrollView:支援巢狀滑動的ScrollView;

屬性

屬性說明預設值
controller滾動監聽
scrollDirection滾動方向Axis.vertical 預設垂直方向
reverse是都倒敘false 預設值
physics控制使用者滾動檢視的互動AlwaysScrollableScrollPhysics 總是可以滑動
NeverScrollableScrollPhysics 禁止滾動
BouncingScrollPhysics 內容超過一屏上拉有回彈效果
ClampingScrollPhysics 包裹內容不會有回彈
headerSliverBuilder摺疊頭部
body滾動元件實體

NestedScrollView摺疊部分使用SliverAppBar來實現

SliverAppBar

程式碼示例

NestedScrollView(
    controller: _scrollController,
    headerSliverBuilder: _headerSliverBuilder,
    body: buildSliverBody(context)
)
///頁面滾動頭部處理
List<Widget> _headerSliverBuilder(BuildContext context, bool innerBoxIsScrolled) {
  return <Widget> [
    buildSliverAppBar(context)
  ];
}
///導航部分渲染
Widget buildSliverAppBar(BuildContext context) {
  return SliverAppBar(
    //當此值為true時 SliverAppBar 會固定在頁面頂部
    //當此值為fase時 SliverAppBar 會隨著滑動向上滑動
    pinned: true,
    //滾動是是否拉伸圖片
    stretch: true,
    //展開區域的高度
    expandedHeight: 500,
    //當snap配置為true時,向下滑動頁面,SliverAppBar(以及其中配置的flexibleSpace內容)會立即顯示出來,
    //反之當snap配置為false時,向下滑動時,只有當ListView的資料滑動到頂部時,SliverAppBar才會下拉顯示出來。
    snap: false,
    //陰影
    elevation: 0,
    //背景顏色
    backgroundColor: headerWhite? Colors.white : Color(0xFFF4F5F7),
    //App bar 的亮度,有白色和黑色兩種主題,預設值為 ThemeData.primaryColorBrightness
    brightness: Brightness.light,
    //在標題左側顯示的一個控制元件,在首頁通常顯示應用的 logo;在其他介面通常顯示為返回按鈕
    leading: IconButton(
        icon: Image.network(backIcon, height: 22, width: 22,),
        onPressed: (){
          //TODO: 返回事件處理
        }
    ),
        //一個顯示在 AppBar 下方的控制元件,高度和 AppBar 高度一樣, // 可以實現一些特殊的效果,該屬性通常在 SliverAppBar 中使用
    flexibleSpace: FlexibleSpaceBar(
      title: headerWhite ? Text('長津湖', style: TextStyle(
          color: Color(0xFF333333),
          fontWeight: FontWeight.w700,
          fontSize: 17,
          fontFamily: 'PingFangSC-Semibold'
      ),) : Text(''),
      //標題居中
      centerTitle: true,
      background: buildAppBarBackground(context),
    ),
  );
}

屬性

const SliverAppBar({
    Key key,
    this.leading,         //在標題左側顯示的一個控制元件,在首頁通常顯示應用的 logo;在其他介面通常顯示為返回按鈕
    this.automaticallyImplyLeading = true,//? 控制是否應該嘗試暗示前導小部件為null
    this.title,               //當前介面的標題文字
    this.actions,          //一個 Widget 列表,代表 Toolbar 中所顯示的選單,對於常用的選單,通常使用 IconButton 來表示;對於不常用的選單通常使用 PopupMenuButton 來顯示為三個點,點選後彈出二級選單
    this.flexibleSpace,        //一個顯示在 AppBar 下方的控制元件,高度和 AppBar 高度一樣, // 可以實現一些特殊的效果,該屬性通常在 SliverAppBar 中使用
    this.bottom,         //一個 AppBarBottomWidget 物件,通常是 TabBar。用來在 Toolbar 標題下面顯示一個 Tab 導航欄
    this.elevation,            //陰影
    this.forceElevated = false, 
    this.backgroundColor,       //APP bar 的顏色,預設值為 ThemeData.primaryColor。改值通常和下面的三個屬性一起使用
    this.brightness,   //App bar 的亮度,有白色和黑色兩種主題,預設值為 ThemeData.primaryColorBrightness
    this.iconTheme,  //App bar 上圖示的顏色、透明度、和尺寸資訊。預設值為 ThemeData().primaryIconTheme
    this.textTheme,    //App bar 上的文字主題。預設值為 ThemeData().primaryTextTheme
    this.primary = true,  //此應用欄是否顯示在螢幕頂部
    this.centerTitle,     //標題是否居中顯示,預設值根據不同的作業系統,顯示方式不一樣,true居中 false居左
    this.titleSpacing = NavigationToolbar.kMiddleSpacing,//橫軸上標題內容 周圍的間距
    this.expandedHeight,     //展開高度
    this.floating = false,       //是否隨著滑動隱藏標題
    this.pinned = false,  //是否固定在頂部
    this.snap = false,   //與floating結合使用
  })

flexibleSpace

flexibleSpace: FlexibleSpaceBar(
  //是否展示標題
  title: headerWhite ? Text('長津湖', style: TextStyle(
      color: Color(0xFF333333),
      fontWeight: FontWeight.w700,
      fontSize: 17,
      fontFamily: 'PingFangSC-Semibold'
  ),) : Text(''),
  //標題居中
  centerTitle: true,
  //摺疊部分背景圖片
  background: Container(
      height: 400,
      width: ScreenUtil().screenWidth,
      decoration: BoxDecoration(
          image: DecorationImage(
              image: NetworkImage('https://p0.meituan.net/movie/0e81560dc9910a6a658a82ec7a054ceb5075992.jpg@464w_644h_1e_1c'),
              fit: BoxFit.fill
          )
      ),
    ),
)

展示標題如下:

image-20211115145812098

不展示標題滾動到某個位置時在展示 如下:

image-20211115145916035

完整程式碼

完整程式碼

相關文章