flutter列表常见的两种吸附置顶效果

效果一:
SVID_20201125_154558_1.gif

完整代码代码:

import 'package:flutter/material.dart';

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

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

  List _tabViews = [
    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: [
          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: [
          // 背景图
          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: [
                      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 createState() {
    return CustomScrollView1State();
  }
}

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

  List _tabViews = [
    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: [
          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;
  }
}

你可能感兴趣的:(flutter列表常见的两种吸附置顶效果)