ListView
可滚动组件都有一个 controller 属性的 ScrollController,通过它可以进行一些滚动设置,
比如 jumpTo(double offset)和animateTo(double offset,...)
ScrollController _controller = ScrollController(
initialScrollOffset: 1000, //初始滚动到的位置
keepScrollOffset: true, //是否记录滚动位置
);
//如果需要在路由跳转时记录滚动位置,不仅要设置keepScrollOffset,同时还要设置
//key: PageStorageKey(1), 数字用于区分页面中多个滚动视图时使用
1. 默认构造
ListView(
shrinkWrap: true
padding: const EdgeInsets.all(10),
children:
[
Text("第一段文字"),
Text("第二段文字"),
Text("第三段文字"),
Text("第四段文字"),
Text("第五段文字"),
Text("第六段文字"),
],
);
2. builder构造
ListView.builder(
key: PageStorageKey(1), //保存滚动位置
controller: controller,
itemExtent: 100,
itemCount: 50,
padding: EdgeInsets.all(10),
itemBuilder: (BuildContext context, int index) {
return Container(
color: index % 2 == 0 ? Colors.red : Colors.green,
child: ListTile(title: Text("a----$index")),
);
},
)
3. separated构造
ListView.separated(
itemCount: 10,
padding: EdgeInsets.all(10),
separatorBuilder: (BuildContext context, int index) {
return Text("这是第$index行文字");
},
itemBuilder: (BuildContext context, int index) {
return const DecoratedBox(
decoration: BoxDecoration(color: Colors.green),
child: SizedBox(height: 10),
);
},
)
GridView
普通构造
GridView主要通过gridDelegate 进行布局,SliverGridDelegate共有两个子类可以直接使用:
1. SliverGridDelegateWithFixedCrossAxisCount
固定交叉轴条目数量
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 30, //主轴方向的间距
crossAxisCount: 3, //横轴三个子widget
crossAxisSpacing: 20, //交叉轴方向的间距
childAspectRatio: 1.0, //子widget宽高比为1
),
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)
],
)
类似于 count 构造方法
GridView.count(
crossAxisCount: 150,
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
],
)
2. SliverGridDelegateWithMaxCrossAxisExtent
指定条目在交叉轴方向的最大尺寸
GridView(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100.0, //子元素在横轴上的最大长度
childAspectRatio: 2.0, //宽高比为2
),
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)
],
)
类似于 extent构造方法
GridView.extent(
maxCrossAxisExtent: 150,
children: <Widget>[
Icon(Icons.ac_unit),
Icon(Icons.airport_shuttle),
Icon(Icons.all_inclusive),
Icon(Icons.beach_access),
Icon(Icons.cake),
],
)
以上两种方式都强制约束条目组件尺寸,所以单纯的GridView 无法实现瀑布流效果。 另外这种方式不适合创建条目数量较大的列表。
builder/custom 构造
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 30 ),
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Icon(Icons.ac_unit);
},
)
PageView
@override
Widget build(BuildContext context) {
var children = <Widget>[];
// 生成 6 个单独页面
for (int i = 0; i < 6; ++i) {
children.add( Page( text: '$i'));
}
return PageView(
// scrollDirection: Axis.vertical, // 滑动方向为垂直方向
//controller:PageController(), //控制器
pageSnapping:true, //是否整页滑动
children: children,
);
}
TabBarView
一般是顶部TabBar,下面TabBarView,通过同一个控制器进行联动
AppBar.bottom通常是TabBar等,通过PreferredSize可设置为任意组件
Scaffold(
appBar: AppBar(
backgroundColor: ColorRes.public_00A99A,
centerTitle: true, //居中展示 !!!
title: const Text('资讯'),
bottom: _customTab(state.tabs),//TabBar 一般在底部
),
//TabBarView一般做页面body
body: TabBarView(
controller: _tabController,
children: _itemPage(state.tabs),
),
),
生成TabBar
TabBar(
//是否滚动
isScrollable: true,
//对数组的遍历处理
tabs: tab.map<Tab>((e) => Tab(text: e.name)).toList(),
//和TabBarView控制器
controller: _tabController,
// 选中指示条颜色
indicatorColor: ColorRes.public_5083AA,
//选中或未选中时文字颜色及
labelColor: ColorRes.public_000000,
unselectedLabelColor: ColorRes.public_999999,
// 未选择尺寸
indicatorSize: TabBarIndicatorSize.label,
//style里面设置颜色无效
labelStyle: const TextStyle(
fontSize: DimenRes.public_18, fontWeight: FontWeight.bold),
unselectedLabelStyle: const TextStyle(
fontSize: DimenRes.public_16, fontWeight: FontWeight.bold),
),
注意
由于TabBarView 与 TabBar 需要联动,所以必须初始化 下,TabController,
同时还要混入TickerProviderStateMixin,同时还需要注意释放的问题,
_tabController = TabController(
length: state.tabs.length,
vsync: this, //固定写法
);
所以实赋中直接用·DefaultTabController`做为父组件,就可以避免创建控制器和混入方法的问题。
DefaultTabController(
length: state.tabs.length,
child: Scaffold(
appBar: AppBar(
backgroundColor: ColorRes.public_00A99A,
centerTitle: true, //居中展示 !!!
title: const Text('资讯'),
bottom: _customTab(state.tabs),
),
body: TabBarView(
children: _itemPage(state.tabs),
),
),
);