列表是APP的核心功能,目前这个库不算完善,以后国外的大神应该会补全,现在的样式就是很基础的东西,解决一些常用的加载,至于后面的自定义tag需要一个过程,混合布局可以参考flutter_staggered_grid_view,下面是基础的写法:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random();
return new MaterialApp(
title: 'ListView3+GridView33',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
// fontFamily: 'fontdemo1'
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('图片加载'),
),
body: new Center(
// child: new ListView(
// shrinkWrap: true,
// padding: const EdgeInsets.all(20.0),
// children: <Widget>[
// const Text('I\'m dedicating every day to you'),
// const Text('Domestic life was never quite my style'),
// const Text('When you smile, you knock me out, I fall apart'),
// const Text('And I thought I was so smart'),
// ],
// ),
// child: new ListView3(),
// child: new GridView3(),
// child: new GridView33(),
child: new InfiniteGridView(),
),
),
);
}
}
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;
},
);
}
}
class GridView3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //横轴三个子widget
childAspectRatio: 1.0, //宽高比为1时,子widget
),
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)
]);
}
}
class GridView33 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GridView(
padding: EdgeInsets.zero,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 120.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),
],
);
}
}
class InfiniteGridView extends StatefulWidget {
@override
_InfiniteGridViewState createState() => new _InfiniteGridViewState();
}
class _InfiniteGridViewState extends State<InfiniteGridView> {
List<IconData> _icons = []; //保存Icon数据
@override
void initState() {
// 初始化数据
_retrieveIcons();
}
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, //每行三列
childAspectRatio: 1.0 //显示区域宽高相等
),
itemCount: _icons.length,
itemBuilder: (context, index) {
//如果显示到最后一个并且Icon总数小于200时继续获取数据
if (index == _icons.length - 1 && _icons.length < 200) {
_retrieveIcons();
}
return Icon(_icons[index]);
}
);
}
//模拟异步获取数据
void _retrieveIcons() {
Future.delayed(Duration(milliseconds: 200)).then((e) {
setState(() {
_icons.addAll([
Icons.ac_unit,
Icons.airport_shuttle,
Icons.all_inclusive,
Icons.beach_access, Icons.cake,
Icons.free_breakfast
]);
});
});
}
}
ListView+GridView图文混合:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random();
return new MaterialApp(
title: 'ListView+GridView综合布局',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
// fontFamily: 'fontdemo1'
),
home: new Scaffold(
// appBar: new AppBar(
title: new Text('图片加载'),
),
body: new Center(
// child: new ListView(
// shrinkWrap: true,
// padding: const EdgeInsets.all(20.0),
// children: <Widget>[
// const Text('I\'m dedicating every day to you'),
// const Text('Domestic life was never quite my style'),
// const Text('When you smile, you knock me out, I fall apart'),
// const Text('And I thought I was so smart'),
// ],
// ),
// child: new ListView3(),
// child: new GridView3(),
// child: new GridView33(),
child: new CustomScrollViewTestRoute(),
),
),
);
}
}
class CustomScrollViewTestRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
//因为本路由没有使用Scaffold,为了让子级Widget(如Text)使用
//Material Design 默认的样式风格,我们使用Material作为本路由的根。
return Material(
child: CustomScrollView(
slivers: <Widget>[
//AppBar,包含一个导航栏
SliverAppBar(
//标题居中
centerTitle: true,
leading: Builder(builder: (context) {
return IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white), //自定义图标
onPressed: () {
//
},
);
}),
// leading: Icon(
// Icons.arrow_back,
// ),
//展开高度250
expandedHeight: 250.0,
//不随着滑动隐藏标题
floating: false,
//固定在顶部
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: const Text('YUN'),
background: Image.asset(
"assets/images/food04.jpeg",
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个列表项
),
),
],
),
);
}
}
滚动监听及控制:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
//Stateless widgets 是不可变的, 这意味着它们的属性不能改变 - 所有的值都是最终的.
//Stateful widgets 持有的状态可能在widget生命周期中发生变化. 实现一个 stateful widget 至少需要两个类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// final wordPair = new WordPair.random();
return new MaterialApp(
title: '滚动监听及控制',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
// fontFamily: 'fontdemo1'
),
home: new Scaffold(
appBar: new AppBar(
title: new Text('滚动监听及控制'),
),
body: new Center(
// child: new ListView(
// shrinkWrap: true,
// padding: const EdgeInsets.all(20.0),
// children: <Widget>[
// const Text('I\'m dedicating every day to you'),
// const Text('Domestic life was never quite my style'),
// const Text('When you smile, you knock me out, I fall apart'),
// const Text('And I thought I was so smart'),
// ],
// ),
// child: new ListView3(),
// child: new GridView3(),
// child: new GridView33(),
child: new ScrollControllerTestRoute(),
// child: new ScrollNotificationTestRoute(),
),
),
);
}
}
class ScrollControllerTestRoute extends StatefulWidget {
@override
ScrollControllerTestRouteState createState() {
return new ScrollControllerTestRouteState();
}
}
class ScrollControllerTestRouteState extends State<ScrollControllerTestRoute> {
ScrollController _controller = new ScrollController();
bool showToTopBtn = false; //是否显示“返回到顶部”按钮
@override
void initState() {
//监听滚动事件,打印滚动位置
_controller.addListener(() {
print(_controller.offset); //打印滚动位置
if (_controller.offset < 1000 && showToTopBtn) {
setState(() {
showToTopBtn = false;
});
} else if (_controller.offset >= 1000 && showToTopBtn == false) {
setState(() {
showToTopBtn = true;
});
}
});
}
@override
void dispose() {
//为了避免内存泄露,需要调用_controller.dispose
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(title: Text("滚动控制")),
body: Scrollbar(
child: ListView.builder(
itemCount: 100,
itemExtent: 50.0, //列表项高度固定时,显式指定高度是一个好习惯(性能消耗小)
controller: _controller,
itemBuilder: (context, index) {
return ListTile(
title: Text("$index"),
);
}),
),
floatingActionButton: !showToTopBtn
? null
: FloatingActionButton(
child: Icon(Icons.arrow_upward),
onPressed: () {
//返回到顶部时执行动画
_controller.animateTo(.0,
duration: Duration(milliseconds: 200), curve: Curves.ease);
}),
);
}
}
class ScrollNotificationTestRoute extends StatefulWidget {
@override
_ScrollNotificationTestRouteState createState() =>
new _ScrollNotificationTestRouteState();
}
class _ScrollNotificationTestRouteState
extends State<ScrollNotificationTestRoute> {
String _progress = "0%"; //保存进度百分比
@override
Widget build(BuildContext context) {
return Scrollbar(
//进度条
// 监听滚动通知
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
double progress = notification.metrics.pixels /
notification.metrics.maxScrollExtent;
//重新构建
setState(() {
_progress = "${(progress * 100).toInt()}%";
});
print("BottomEdge: ${notification.metrics.extentAfter == 0}");
//return true; //放开此行注释后,进度条将失效
},
child: Stack(
alignment: Alignment.center,
children: <Widget>[
ListView.builder(
itemCount: 100,
itemExtent: 50.0,
itemBuilder: (context, index) {
return ListTile(title: Text("$index"));
}),
CircleAvatar(
//显示进度百分比
radius: 30.0,
child: Text(_progress),
backgroundColor: Colors.black54,
)
],
),
),
);
}
}
总结:学完网络请求,大家把tolist里面改写就可以独立出来不同的样式去加载数据,还是挺方便的,代码精简不少~加油~
转载于:https://blog.51cto.com/liangxiao/2386262