flutter列表常見的兩種吸附置頂效果

效果一:
SVID_20201125_154558_1.gif

完整代碼代碼:

import 'package:flutter/material.dart';

class CustomScrollView1 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return CustomScrollView1State();
  }
}

class CustomScrollView1State extends State<CustomScrollView1>
    with SingleTickerProviderStateMixin {
  List<Widget> _tabs = <Widget>[
    Tab(
      text: "Home",
    ),
    Tab(
      text: "Profile",
    )
  ];

  List<Widget> _tabViews = <Widget>[
    Center(child: Text("Home")),
    Center(child: Text("Profile")),
  ];

  TabController _tabController;

  @override
  void initState() {
    super.initState();
    this._tabController = TabController(length: _tabs.length, vsync: this);
  }

  @override
  void dispose() {
    this._tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverPersistentHeader(
            floating: true,
            pinned: true,
            delegate: SliverCustomHeaderDelegate(
              collapsedHeight: 43.0,
              expandedHeight: 220.0,
              paddingTop: 27.0,
              coverImgUrl:
                  "http://img1.mukewang.com/5c18cf540001ac8206000338.jpg",
              title: "練習",
            ),
          ),
          SliverFillRemaining(
            child: TabBarView(
              controller: this._tabController,
              children: _tabViews,
            ),
          ),
        ],
      ),
    );
  }
}

class SliverCustomHeaderDelegate extends SliverPersistentHeaderDelegate {
  final double collapsedHeight;

  ///折疊的高度
  final double expandedHeight;

  ///展開的高度
  final double paddingTop;
  final String coverImgUrl;
  final String title;

  SliverCustomHeaderDelegate({
    this.collapsedHeight,
    this.expandedHeight,
    this.paddingTop,
    this.coverImgUrl,
    this.title,
  });

  Color makeStickyHeaderBgColor(shrinkOffset) {
    final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255)
        .clamp(0, 255)
        .toInt();
    return Color.fromARGB(alpha, 255, 255, 255);
  }

  Color makeStickyHeaderTextColor(shrinkOffset, isIcon) {
    if (shrinkOffset <= 50) {
      return isIcon ? Colors.white : Colors.transparent;
    } else {
      final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255)
          .clamp(0, 255)
          .toInt();
      return Color.fromARGB(alpha, 0, 0, 0);
    }
  }

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      height: this.maxExtent,
      width: MediaQuery.of(context).size.width,
      child: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          // 背景圖
          Container(child: Image.network(this.coverImgUrl, fit: BoxFit.cover)),
          // 收起頭部
          Positioned(
            left: 0,
            right: 0,
            top: 0,
            child: Container(
              color: this.makeStickyHeaderBgColor(shrinkOffset), // 背景顏色
              child: SafeArea(
                bottom: false,
                child: Container(
                  height: this.collapsedHeight,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      IconButton(
                        icon: Icon(
                          Icons.arrow_back_ios,
                          color: this.makeStickyHeaderTextColor(
                              shrinkOffset, true), // 返回圖標顏色
                        ),
                        onPressed: () => Navigator.pop(context),
                      ),
                      Text(
                        this.title,
                        style: TextStyle(
                          fontSize: 20,
                          fontWeight: FontWeight.w500,
                          color: this.makeStickyHeaderTextColor(
                              shrinkOffset, false), // 標題顏色
                        ),
                      ),
                      IconButton(
                        icon: Icon(
                          Icons.share,
                          color: this.makeStickyHeaderTextColor(
                              shrinkOffset, true), // 分享圖標顏色
                        ),
                        onPressed: () {},
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  double get maxExtent => this.expandedHeight;

  @override
  double get minExtent => this.collapsedHeight + this.paddingTop;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }
}

效果二:
SVID_20201125_155856_1.gif

完整代碼:

import 'package:flutter/material.dart';

class CustomScrollView1 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return CustomScrollView1State();
  }
}

class CustomScrollView1State extends State<CustomScrollView1>
    with SingleTickerProviderStateMixin {
  List<Widget> _tabs = <Widget>[
    Tab(
      text: "Home",
    ),
    Tab(
      text: "Profile",
    )
  ];

  List<Widget> _tabViews = <Widget>[
    Center(child: Text("Home")),
    Center(child: Text("Profile")),
  ];

  TabController _tabController;

  @override
  void initState() {
    super.initState();
    this._tabController = TabController(length: _tabs.length, vsync: this);
  }

  @override
  void dispose() {
    this._tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            floating: true,
            snap: true,
            pinned: true,
            expandedHeight: 250.0,
            flexibleSpace: FlexibleSpaceBar(
              title: Text("標題"),
              background: Image(
                image: AssetImage("images/sealand.jpeg"),
                fit: BoxFit.cover,
              ),
            ),
          ),
          SliverPersistentHeader(
            floating: true,
            pinned: true,
            delegate: StickyTabBarDelegate(
              TabBar(
                controller: _tabController,
                labelColor: Colors.black,
                tabs: _tabs,
              ),
            ),
          ),
          SliverFillRemaining(
            child: TabBarView(
              controller: this._tabController,
              children: _tabViews,
            ),
          ),
        ],
      ),
    );
  }
}

class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
  final TabBar child;

  StickyTabBarDelegate(this.child);

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return this.child;
  }

  @override
  double get maxExtent => this.child.preferredSize.height;

  @override
  double get minExtent => this.child.preferredSize.height;

  @override
  bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凄杯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蒜魄,更是在濱河造成了極大的恐慌专肪,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柄错,死亡現(xiàn)場離奇詭異,居然都是意外死亡苦酱,警方通過查閱死者的電腦和手機售貌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躏啰,“玉大人,你說我怎么就攤上這事耙册「” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵详拙,是天一觀的道長帝际。 經(jīng)常有香客問我,道長饶辙,這世上最難降的妖魔是什么蹲诀? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮弃揽,結(jié)果婚禮上脯爪,老公的妹妹穿的比我還像新娘。我一直安慰自己矿微,他們只是感情好痕慢,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涌矢,像睡著了一般掖举。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上娜庇,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天塔次,我揣著相機與錄音方篮,去河邊找鬼。 笑死励负,一個胖子當著我的面吹牛藕溅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播熄守,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼蜈垮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了裕照?” 一聲冷哼從身側(cè)響起攒发,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晋南,沒想到半個月后惠猿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡负间,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年偶妖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片政溃。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡趾访,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出董虱,到底是詐尸還是另有隱情扼鞋,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布愤诱,位于F島的核電站云头,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淫半。R本人自食惡果不足惜溃槐,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望科吭。 院中可真熱鬧昏滴,春花似錦、人聲如沸对人。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽规伐。三九已至蟹倾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲜棠。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工肌厨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人豁陆。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓柑爸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親盒音。 傳聞我的和親對象是個殘疾皇子表鳍,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容