标签:list item 包含 grid vertica 区别 就是 不同 less tle
在Flutter中,术语ViewPort(视口),如无特别说明,则是指一个Widget的实际显示区域。例如,一个ListView的显示区域高度是800像素,虽然其列表项总高度可能远远超过800像素,但是其ViewPort仍然是800像素。
在可滚动widget的坐标描述中,通常将滚动方向称为主轴,非滚动方向称为纵轴。由于可滚动widget的默认方向一般都是沿垂直方向,所以默认情况下主轴就是指垂直方向,水平方向同理。
当内容超过显示视口(ViewPort)时,如果没有特殊处理,Flutter则会提示Overflow错误。为此,Flutter提供了多种可滚动widget(Scrollable Widget)用于显示列表和长布局。可滚动Widget都直接或间接包含一个Scrollable widget:
Scrollable({
...
this.axisDirection = AxisDirection.down,
this.controller,
this.physics,
@required this.viewportBuilder, //后面介绍
})
Scrollbar是一个Material风格的滚动指示器(滚动条),如果要给可滚动widget添加滚动条,只需将Scrollbar作为可滚动widget的父widget即可,如:
Scrollbar(
child: SingleChildScrollView(
...
),
);
SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子Widget。定义如下:
SingleChildScrollView({
this.scrollDirection = Axis.vertical, //滚动方向,默认是垂直方向
this.reverse = false,
this.padding,
bool primary,
this.physics,
this.controller,
this.child,
})
除了通用属性,我们重点看一下reverse和primary两个属性:
ListView是最常用的可滚动widget,它可以沿一个方向线性排布所有子widget。我们看看ListView的默认构造函数定义:
ListView({
...
//可滚动widget公共参数
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
EdgeInsetsGeometry padding,
//ListView各个构造函数的共同参数
double itemExtent,
bool shrinkWrap = false,
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
double cacheExtent,
//子widget列表
List<Widget> children = const <Widget>[],
})
itemExtent:该参数如果不为null,则会强制children的"长度"为itemExtent的值;这里的"长度"是指滚动方向上子widget的长度,即如果滚动方向是垂直方向,则itemExtent代表子widget的高度,如果滚动方向为水平方向,则itemExtent代表子widget的长度。
shrinkWrap:该属性表示是否根据子widget的总长度来设置ListView的长度,默认值为false 。默认情况下,ListView的会在滚动方向尽可能多的占用空间。当ListView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true。
addAutomaticKeepAlives:该属性表示是否将列表项(子widget)包裹在AutomaticKeepAlive widget中;典型地,在一个懒加载列表中,如果将列表项包裹在AutomaticKeepAlive中,在该列表项滑出视口时该列表项不会被GC,它会使用KeepAliveNotification来保存其状态。如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。
addRepaintBoundaries:该属性表示是否将列表项(子widget)包裹在RepaintBoundary中。当可滚动widget滚动时,将列表项包裹在RepaintBoundary中可以避免列表项重绘,但是当列表项重绘的开销非常小(如一个颜色块,或者一个较短的文本)时,不添加RepaintBoundary反而会更高效。和addAutomaticKeepAlive一样,如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。
ListView.builder适合列表项比较多(或者无限)的情况,因为只有当子Widget真正显示的时候才会被创建。下面看一下ListView.builder的核心参数列表:
ListView.builder({
// ListView公共参数已省略
...
@required IndexedWidgetBuilder itemBuilder,
int itemCount,
...
})
ListView.separated可以生成列表项之间的分割器,它除了比ListView.builder多了一个separatorBuilder参数,该参数是一个分割器生成器。
class ListView3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
//下划线widget预定义以供复用。
Widget divider1=Divider(color: Colors.blue,);
Widget divider2=Divider(color: Colors.green);
return ListView.separated(
itemCount: 100,
//列表项构造器
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("$index"));
},
//分割器构造器
separatorBuilder: (BuildContext context, int index) {
return index%2==0?divider1:divider2;
},
);
}
}
GridView可以构建一个二维网格列表,其默认构造函数定义如下:
GridView({
Axis scrollDirection = Axis.vertical,
bool reverse = false,
ScrollController controller,
bool primary,
ScrollPhysics physics,
bool shrinkWrap = false,
EdgeInsetsGeometry padding,
@required SliverGridDelegate gridDelegate, //控制子widget layout的委托
bool addAutomaticKeepAlives = true,
bool addRepaintBoundaries = true,
double cacheExtent,
List<Widget> children = const <Widget>[],
})
SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法,Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent:
该子类实现了一个横轴为固定数量子元素的layout算法,其构造函数为:
SliverGridDelegateWithFixedCrossAxisCount({
@required double crossAxisCount,
double mainAxisSpacing = 0.0,
double crossAxisSpacing = 0.0,
double childAspectRatio = 1.0,
})
可以发现,子元素的大小是通过crossAxisCount和childAspectRatio两个参数共同决定的。
GridView.count构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的GridView:
GridView.count(
crossAxisCount: 3,
childAspectRatio: 1.0,
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
);
该子类实现了一个横轴子元素为固定最大长度的layout算法,其构造函数为:
SliverGridDelegateWithMaxCrossAxisExtent({
double maxCrossAxisExtent,
double mainAxisSpacing = 0.0,
double crossAxisSpacing = 0.0,
double childAspectRatio = 1.0,
})
GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建纵轴子元素为固定最大长度的的GridView:
GridView.extent(
maxCrossAxisExtent: 120.0,
childAspectRatio: 2.0,
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
Icon(Icons.free_breakfast),
],
);
上面我们介绍的GridView都需要一个Widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子Widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子Widget。GridView.builder 必须指定的参数有两个:
GridView.builder(
...
@required SliverGridDelegate gridDelegate,
@required IndexedWidgetBuilder itemBuilder,
)
其中itemBuilder为子widget构建器。
CustomScrollView是可以使用sliver来自定义滚动模型(效果)的widget。它可以包含多种滚动模型,举个例子,假设有一个页面,顶部需要一个GridView,底部需要一个ListView,而要求整个页面的滑动效果是统一的,即它们看起来是一个整体,如果使用GridView+ListView来实现的话,就不能保证一致的滑动效果,因为它们的滚动效果是分离的,所以这时就需要一个"胶水",把这些彼此独立的可滚动widget(Sliver)"粘"起来,而CustomScrollView的功能就相当于“胶水”。
Sliver有细片、小片之意,在Flutter中,Sliver通常指具有特定滚动效果的可滚动块。可滚动widget,如ListView、GridView等都有对应的Sliver实现如SliverList、SliverGrid等。对于大多数Sliver来说,它们和可滚动Widget最主要的区别是Sliver不会包含Scrollable Widget,也就是说Sliver本身不包含滚动交互模型 ,正因如此,CustomScrollView才可以将多个Sliver"粘"在一起,这些Sliver共用CustomScrollView的Scrollable,最终实现统一的滑动效果。
示例
import 'package:flutter/material.dart';
class CustomScrollViewTestRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
//因为本路由没有使用Scaffold,为了让子级Widget(如Text)使用
//Material Design 默认的样式风格,我们使用Material作为本路由的根。
return Material(
child: CustomScrollView(
slivers: <Widget>[
//AppBar,包含一个导航栏
SliverAppBar(
pinned: true,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: const Text('Demo'),
background: Image.asset(
"./images/avatar.png", fit: BoxFit.cover,),
),
),
SliverPadding(
padding: const EdgeInsets.all(8.0),
sliver: new SliverGrid( //Grid
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, //Grid按两列显示
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
//创建子widget
return new Container(
alignment: Alignment.center,
color: Colors.cyan[100 * (index % 9)],
child: new Text('grid item $index'),
);
},
childCount: 20,
),
),
),
//List
new SliverFixedExtentList(
itemExtent: 50.0,
delegate: new SliverChildBuilderDelegate(
(BuildContext context, int index) {
//创建列表项
return new Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: new Text('list item $index'),
);
},
childCount: 50 //50个列表项
),
),
],
),
);
}
}
代码分为三部分:
标签:list item 包含 grid vertica 区别 就是 不同 less tle
原文地址:https://www.cnblogs.com/SLchuck/p/10332150.html