Flutter CustomScrollView 自定义滑动效果
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter CustomScrollView 自定义滑动效果相关的知识,希望对你有一定的参考价值。
参考技术A基本和AppBar一样,只是他只能在CustomScrollView中使用,应该很常见,滑动的时候固定appbar,就需要用到他.
大部分和appbar一样,主要说下重要的几个:
是否将导航栏部分固定在appbar的位置.这个需求在实际中很常用. 看看效果图.
当 pinned = false:
可以看到appbar并没有固定在最上面,而是根据内容划出了界面.
当 pinned = true :
这个应该是需求中经常用到的效果了.
当floating = false :
当floating = true:
仔细看 ,区别是在列表整体向下滑动时,appbar开始显示的位置不同.
当为false时 ,向下滑动时,会先降列表内容滑动顶部,然后appbar会跟着列表滑动显示出来.如上图
当为true时, 向下滑动时,appbar会先跟着列表滑动显示出来. 然后继续列表的滑动. 如上图
不能单独使用要配合 ****floating 和 ****pinned
具体效果看官网地址
是否展开,默认false,直接看值为true的效果图,就明白了.
可以再里面添加扩展的内容:
通过测试发现 **后面不是 FlexibleSpaceBar 的话, stretch = true 无效. **
和Padding一样.子控件是 sliver 类型...
上图中在padding中添加了一个背景色为青色的容器widget
里面可以设置不是 sliver 类型的widget。如上图中的 padding中添加的 container
就两个协议,一个是布局协议一个展示协议.基本和GridView一样.也有count和extext... 不设置个数默认无数个
SliverChildListDelegate 这种方式前提是知道cell个数,比较少,好搭建
SliverChildBuilderDelegate 这种方式,可以根据数组去创建,不知道cell个数
和listview差不多.也是协议 不设置个数默认无数个
flutter学习之CustomScrollView
CustomScrollView
CustomScrollView是可以使用Sliver来自定义滚动模型(效果)的组件。它可以包含多种滚动模型。包括header,footer,以及类似Android Coordinglayout布局的滑动效果,CustomScrollView可以实现把多个彼此独立的可滑动widget组合起来
Sliver的概念
Flutter中提出一个Sliver(中文为“薄片”的意思)概念,如果一个可滚动组件支持Sliver模型,那么该滚动可以将子组件分成好多个“薄片”(Sliver),只有当Sliver出现在视口中时才会去构建它,这种模型也称为“基于Sliver的延迟构建模型”。可滚动组件中有很多都支持基于Sliver的延迟构建模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView。
这个跟安卓的思维是一致的,类似与分页加载,复用加载,数据量比较大的时候对提高加载效率非常有帮助。SingleChildScrollView只包含一个子widget,本身也只适用于子widget数量有限的场景。
1、添加Header和Footer
import 'dart:ui';
import 'package:flutter/material.dart';
class CsWidget extends StatelessWidget
@override
Widget build(BuildContext context)
// TODO: implement build
return Scaffold(
appBar: PreferredSize(
preferredSize:
Size.fromHeight(MediaQueryData.fromWindow(window).padding.top),
child: SafeArea(
top: true,
child: Offstage(),
),
),
body: CustomScrollViewWidget(),
);
class CustomScrollViewWidget extends StatelessWidget
@override
Widget build(BuildContext context)
// TODO: implement build
return CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
SliverAppBar(
pinned: false,
expandedHeight: 250.0,
backgroundColor: Colors.blue,
flexibleSpace: FlexibleSpaceBar(
background: Image.network("http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg",fit: BoxFit.cover,),
),
),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
color: Colors.red,
alignment: Alignment.center,
child: Text("$index"),
);
, childCount: 20),
itemExtent: 50),
SliverAppBar(
pinned: false,
expandedHeight: 250.0,
backgroundColor: Colors.blue,
flexibleSpace: FlexibleSpaceBar(
background: Image.network("http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg",fit: BoxFit.cover,),
),
),
],
);
CustomScrollView里添加的子widget都必须是Sliver,比如添加Image或者Text都会报错
分析一下SliverAppBar
SliverAppBar
const SliverAppBar(
Key key,
this.leading,//左侧的图标或文字,多为返回箭头
this.automaticallyImplyLeading = true,//没有leading为true的时候,默认返回箭头,没有leading且为false,则显示title
this.title,//标题
this.actions,//标题右侧的操作
this.flexibleSpace,//可以理解为SliverAppBar的背景内容区
this.bottom,//SliverAppBar的底部区
this.elevation,//阴影
this.forceElevated = false,//是否显示阴影
this.backgroundColor,//背景颜色
this.brightness,//状态栏主题,默认Brightness.dark,可选参数light
this.iconTheme,//SliverAppBar图标主题
this.actionsIconTheme,//action图标主题
this.textTheme,//文字主题
this.primary = true,//是否显示在状态栏的下面,false就会占领状态栏的高度
this.centerTitle,//标题是否居中显示
this.titleSpacing = NavigationToolbar.kMiddleSpacing,//标题横向间距
this.expandedHeight,//合并的高度,默认是状态栏的高度加AppBar的高度
this.floating = false,//滑动时是否悬浮
this.pinned = false,//标题栏是否固定
this.snap = false,//配合floating使用
)
其中比较常用的leading,title,actions,backgroundColor,flexibleSpace,pinned,expandedHeight
class CustomScrollViewWidget extends StatelessWidget
@override
Widget build(BuildContext context)
// TODO: implement build
return CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
SliverAppBar(
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () ),
title: Text("标题"),
actions: <Widget>[
IconButton(icon: Icon(Icons.share), onPressed: () )
],
primary: true,
pinned: true,
centerTitle: true,
expandedHeight: 250.0,
backgroundColor: Colors.blue,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg",
fit: BoxFit.cover,
),
),
),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
height: 30,
color: index % 2 == 0 ? Colors.red : Colors.purpleAccent,
alignment: Alignment.center,
child: Text("$index"),
);
, childCount: 20),
itemExtent: 50),
],
);
SliverAppBar+SliverGrid+SliverFixedExtentList实现滑动列表
class CustomScrollViewWidget extends StatelessWidget
@override
Widget build(BuildContext context)
// TODO: implement build
return CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
SliverAppBar(
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () ),
title: Text("标题"),
actions: <Widget>[
IconButton(icon: Icon(Icons.share), onPressed: () )
],
primary: true,
pinned: true,
centerTitle: true,
expandedHeight: 250.0,
backgroundColor: Colors.blue,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg",
fit: BoxFit.cover,
),
),
),
SliverPadding(
padding: EdgeInsets.all(20),
sliver: SliverGrid(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
color: index % 2 == 0 ? Colors.greenAccent : Colors.yellow,
alignment: Alignment.center,
child: Text("$index"),
);
, childCount: 8),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
childAspectRatio: 1)),
),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
height: 30,
color: index % 2 == 0 ? Colors.red : Colors.purpleAccent,
alignment: Alignment.center,
child: Text("$index"),
);
, childCount: 20),
itemExtent: 50),
],
);
这样就能实现多维列表+单列表的组合布局。但是距离android的多type布局还有一定距离,因为CustomScrollView子widget必须是Sliver,但是换个思路,gradview和listview的子widget没有这个限制,是否以此作为多type实现的方式呢?
我实验了一下是可以的,由此可以断言,CustomScrollView可以完全实现Android多type布局的效果
class CustomScrollViewWidget extends StatelessWidget
@override
Widget build(BuildContext context)
// TODO: implement build
return CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
SliverAppBar(
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: () ),
title: Text("标题"),
actions: <Widget>[
IconButton(icon: Icon(Icons.share), onPressed: () )
],
primary: true,
pinned: true,
centerTitle: true,
expandedHeight: 250.0,
backgroundColor: Colors.blue,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"http://b-ssl.duitang.com/uploads/blog/201312/04/20131204184148_hhXUT.jpeg",
fit: BoxFit.cover,
),
),
),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
color: Colors.deepPurpleAccent,
alignment: Alignment.center,
child: Text("这只是中间type"),
);
, childCount: 1),
itemExtent: 60),
SliverPadding(
padding: EdgeInsets.all(20),
sliver: SliverGrid(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
color: index % 2 == 0 ? Colors.greenAccent : Colors.yellow,
alignment: Alignment.center,
child: Text("$index"),
);
, childCount: 8),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
childAspectRatio: 1)),
),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
height: 30,
color: index % 2 == 0 ? Colors.red : Colors.purpleAccent,
alignment: Alignment.center,
child: Text("$index"),
);
, childCount: 20),
itemExtent: 50),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
color: Colors.deepPurpleAccent,
alignment: Alignment.center,
child: Text("这只是一个footer"),
);
, childCount: 1),
itemExtent: 60),
SliverFixedExtentList(
delegate:
SliverChildBuilderDelegate((BuildContext context, int index)
return Container(
child: Image.network(
"http://b-ssl.duitang.com/uploads/item/201208/08/20120808125749_UxUu8.jpeg",
height: 60,
fit: BoxFit.fitWidth,
),
);
, childCount: 1),
itemExtent: 60),
],
);
今天的学习就到此为止
以上是关于Flutter CustomScrollView 自定义滑动效果的主要内容,如果未能解决你的问题,请参考以下文章
干货 | Flutter控件CustomScrollView原理解析及应用实践
Flutter CustomScrollView 在没有足够项目时滚动
Flutter 之 CustomScrollView & Slivers
ListView 或 CustomScrollView 中的 Flutter WebView - 在 Android 上因高度而崩溃