Flutter:实现一个滑动头部折叠的动画效果

news/2024/12/22 15:10:13/

更新:关于Slivers的具体用法,请看这篇文章:Flutter:Slivers大家族,让滑动视图的组合变得很简单!

本文写的只是SliverAppBar的用法,实际上使用Slivers可以实现多种折叠效果。

 

Android和iOS中都有类似的滑动折叠效果,Flutter官方也提供了NestedScrollView控件来实现类似的效果,但是因为Flutter的一些特性,布局容易出现溢出,这些坑需要自己处理。

 

  先上效果图:

头部折叠.gif


  效果实现是基于Google的gallery demo中的tabs_demo来实现的,主要是通过NestedScrollView控件来实现。

  头部为一个SliverAppBar,折叠部分的内容都放在了flexibleSpace中。

  全部代码如下:

import 'package:flutter/material.dart';// Each TabBarView contains a _Page and for each _Page there is a list
// of _CardData objects. Each _CardData object is displayed by a _CardItem.const String _kGalleryAssetsPackage = 'flutter_gallery_assets';class _Page {_Page({this.label});final String label;String get id => label[0];@overrideString toString() => '$runtimeType("$label")';
}class _CardData {const _CardData({this.title, this.imageAsset, this.imageAssetPackage});final String title;final String imageAsset;final String imageAssetPackage;
}final Map<_Page, List<_CardData>> _allPages = <_Page, List<_CardData>>{new _Page(label: 'LEFT'): <_CardData>[const _CardData(title: 'Vintage Bluetooth Radio',imageAsset: 'shrine/products/radio.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Sunglasses',imageAsset: 'shrine/products/sunnies.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Clock',imageAsset: 'shrine/products/clock.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Red popsicle',imageAsset: 'shrine/products/popsicle.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Folding Chair',imageAsset: 'shrine/products/lawn_chair.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Green comfort chair',imageAsset: 'shrine/products/chair.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Old Binoculars',imageAsset: 'shrine/products/binoculars.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Teapot',imageAsset: 'shrine/products/teapot.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Blue suede shoes',imageAsset: 'shrine/products/chucks.png',imageAssetPackage: _kGalleryAssetsPackage,),],new _Page(label: 'RIGHT'): <_CardData>[const _CardData(title: 'Beachball',imageAsset: 'shrine/products/beachball.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Dipped Brush',imageAsset: 'shrine/products/brush.png',imageAssetPackage: _kGalleryAssetsPackage,),const _CardData(title: 'Perfect Goldfish Bowl',imageAsset: 'shrine/products/fish_bowl.png',imageAssetPackage: _kGalleryAssetsPackage,),],
};class _CardDataItem extends StatelessWidget {const _CardDataItem({this.page, this.data});static const double height = 272.0;final _Page page;final _CardData data;@overrideWidget build(BuildContext context) {return new Card(child: new Padding(padding: const EdgeInsets.all(16.0),child: new Column(crossAxisAlignment: CrossAxisAlignment.stretch,mainAxisAlignment: MainAxisAlignment.start,children: <Widget>[new Align(alignment:page.id == 'L' ? Alignment.centerLeft : Alignment.centerRight,child: new CircleAvatar(child: new Text('${page.id}')),),new SizedBox(width: 144.0,height: 144.0,child: new Image.asset(data.imageAsset,package: data.imageAssetPackage,fit: BoxFit.contain,),),new Center(child: new Text(data.title,style: Theme.of(context).textTheme.title,),),],),),);}
}class TabsDemo extends StatelessWidget {static const String routeName = '/material/tabs';@overrideWidget build(BuildContext context) {return new DefaultTabController(length: _allPages.length,child: new Scaffold(body: new NestedScrollView(headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {return <Widget>[new SliverOverlapAbsorber(handle:NestedScrollView.sliverOverlapAbsorberHandleFor(context),child: new SliverAppBar(pinned: true,expandedHeight: 300.0,// 这个高度必须比flexibleSpace高度大forceElevated: innerBoxIsScrolled,bottom: PreferredSize(child: new Container(child: new TabBar(tabs: _allPages.keys.map((_Page page) => new Tab(child: new Tab(text: page.label),),).toList(),),color: Colors.redAccent[200],),preferredSize: new Size(double.infinity, 46.0)),// 46.0为TabBar的高度,也就是tabs.dart中的_kTabHeight值,因为flutter不支持反射所以暂时没法通过代码获取flexibleSpace: new Container(child: new Column(children: <Widget>[new AppBar(title: Text("this is title"),),new Expanded(child: new Container(child: Image.asset("images/test.jpg",repeat: ImageRepeat.repeat,),width: double.infinity,),)],),),),),];},body: new TabBarView(children: _allPages.keys.map((_Page page) {return new SafeArea(top: false,bottom: false,child: new Builder(builder: (BuildContext context) {return new CustomScrollView(key: new PageStorageKey<_Page>(page),slivers: <Widget>[new SliverOverlapInjector(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),),new SliverPadding(padding: const EdgeInsets.symmetric(vertical: 8.0,horizontal: 16.0,),sliver: new SliverFixedExtentList(itemExtent: _CardDataItem.height,delegate: new SliverChildBuilderDelegate((BuildContext context, int index) {final _CardData data = _allPages[page][index];return new Padding(padding: const EdgeInsets.symmetric(vertical: 8.0,),child: new _CardDataItem(page: page,data: data,),);},childCount: _allPages[page].length,),),),],);},),);}).toList(),),),),);}
}

 


http://www.ppmy.cn/news/664715.html

相关文章

vue折叠面板如何默认展开第一项

折叠面板 折叠面板官网&#xff1a; 项目展示&#xff1a; 代码展示&#xff1a; 默认展开第一个默认展开第二个默认全部展开默认全部折叠 这里的title名字是自己定义的。绑定的值为name的值。由于这是一个循环嵌套的面板&#xff0c;故而绑定时需要用一个数组格式来接收。…

Html 中表格添加展开(折叠)按钮

简易代码&#xff1a; <html><head><meta http-equiv"Content-Typecontent"text/html; charsetUTF-8" /><title>compatibility assessment</title><script type"text/javascript" src"http://libs.baidu.com/…

html那种折叠文字内容怎么实现,html+css实现文字折叠特效实例

本文主要介绍了html+css实现文字折叠特效实例,分享给大家,具体如下: 效果: 实现: 1. 定义标签: aurora 2. 设置文字基本样式: h1{text-transform: uppercase; letter-spacing: 3px; font-size: 15vw; transform: rotate(-10deg) skew(30deg); position: relative; color…

Pittkai——Android折叠屏生命周期

Android折叠屏生命周期 &#xff08;第一次在CSDN上写文章&#xff0c;随便写写&#xff0c;记录一下&#xff09; 如今随着手机的发展&#xff0c;屏幕从分屏甚至走上了折叠屏的道路&#xff0c;即将推出的谷歌Android Q系统更是支持了折叠屏&#xff0c;但苦于手头没有Androi…

VSCode 折叠展开快捷键 macOS版

查看 commandshiftp 搜索fold和unfold 举例 折叠所有&#xff1a;commandk0(数字0)展开所有&#xff1a;commandkj折叠光标所在代码块&#xff1a;commandk[展开光标所在代码块&#xff1a;commandk]

Android魔术(第五弹)—— 一步步实现滑动折叠列表

目录 1、效果展示 2、效果分析 3、Item布局 3、实现Adapter 4、监听滑动 5、回弹效果 6、总结一下 源码&#xff1a; 1、效果展示 这个效果是一年多前完成的&#xff0c;是模仿了当时喵街app的首页的效果&#xff0c;现在整理出来可能有些过时了&#xff0c;不过一些知识点和思…

JS实现一键展开、折叠所有树节点

在数据分析报表中&#xff0c;通常会有结构树展开的分析报表。在结构树节点较多的时候&#xff0c;逐个进行展开、折叠等操作时&#xff0c;会比较繁琐、费时间、费手劲&#xff1b;此处示例通过点击按钮的方式&#xff0c;使用js实现一键展开、折叠所有的树节点&#xff08;不…

html内容折叠,HTML+CSS入门 文本折叠详解

本篇教程介绍了HTMLCSS入门 文本折叠详解&#xff0c;希望阅读本篇文章以后大家有所收获&#xff0c;帮助大家HTMLCSS入门。 < 先看效果&#xff1a; 收缩状态 展开状态 源代码&#xff1a; html>文本折叠测试 .a-text { font-size: 20px;color: #b30000;cursor: pointer…