这篇博客主要是实现以下功能
- flutter中 ListView的基本使用
- 上拉加载刷新
- 加载提示
准备
//在配置文件中添加这个库我们会随机生成单词
english_words: ^3.1.0
基础代码
下面这部分代码是死的,我就不介绍了,我们重点介绍_MyInfiniteListViewState
这里面的内容
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
void main() => runApp(new InfiniteListView());
class InfiniteListView extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "InfiniteListView",
home: Scaffold(
appBar: AppBar(
title: Text("InfiniteLisView"),
),
body: MyInfiniteListView(),
),
);
}
}
class MyInfiniteListView extends StatefulWidget{
@override
_MyInfiniteListViewState createState() => _MyInfiniteListViewState();
}
主要内容
数据容器
//定义一个结尾的标志和一个初始的数组,数组里面放一个元素防止后面的异常
static const loadingTag = "****loading****";
var _word = <String>[loadingTag];
初始化
@override
void initState() {
//初始化的时候添加20个元素
super.initState();
_retireveData();
}
接下来我们来看这个初始化数据的方法怎么写
/**
* 在新的数组中添加20个单词
*/
void _retireveData(){
Future.delayed(new Duration(seconds: 2)).then((e)=>{
//_word 是一个数组,因为默认有一个元素,所以这里减一没关系
_word.insertAll(_word.length-1,generateWordPairs().take(20).map((e) => e.asPascalCase).toList()),
//每次生成20个单词
//这里用到了 english_words: ^3.1.0这个框架,调用生成单词的函数
//生成完了20个单词之后就要更新界面了
setState(() {
//重新构建列表,这里不用做什么事,空的调用也会提示程序刷新builder
})
});
}
build中的内容
//我们使用这个构造函数,是因为这个构造函数中带有分割线
ListView.separated()
我们来看一下伪代码
ListView.separated(
//这个是对每个item的构建
itemBuilder: (context,index){
是否滑动到最后一条
是: 是否超过100条
是: 显示没有更多数据
否:显示转圈圈,等待加载数据
否:构建下一条数据
}
)
基本上就是这个思路了,我们来看下如果超过100条的写法
//超过100条,不在加载更多的数据了,提示用户
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text("--------我也是有底线的------",
style:TextStyle(color: Colors.grey)),
);
没有超过100条但是滑到底了的写法
//不足100条,继续获取数据
if(_word.length-1<100){
//获取数据
_retireveData();
//加载时显示loading
return Container(
//设置边距
padding: const EdgeInsets.all(16.0),
//居中显示
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
//这是一个转圈的progressBar的widget
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
好了 附上完整代码
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
void main() => runApp(new InfiniteListView());
class InfiniteListView extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "InfiniteListView",
home: Scaffold(
appBar: AppBar(
title: Text("InfiniteLisView"),
),
body: MyInfiniteListView(),
),
);
}
}
class MyInfiniteListView extends StatefulWidget{
@override
_MyInfiniteListViewState createState() => _MyInfiniteListViewState();
}
class _MyInfiniteListViewState extends State<MyInfiniteListView>{
static const loadingTag = "****loading****";
var _word = <String>[loadingTag];
@override
void initState() {
//初始化的时候添加20个元素
super.initState();
_retireveData();
}
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (context,index){
//如果到了末尾,就需要获取数据了,这里判断的依据就是是否和 ***loading***相等
if(_word[index] == loadingTag){
//不足100条,继续获取数据
if(_word.length-1<100){
//获取数据
_retireveData();
//加载时显示loading
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0,),
),
);
}else{
//超过100条,不在加载更多的数据了,提示用户
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text("--------我也是有底线的------",
style:TextStyle(color: Colors.grey)),
);
}
}
return ListTile(title: Text("${_word[index]} $index"),);
},
//这里表示的是默认的分割线
separatorBuilder: (context, index)=>Divider(),
itemCount: _word.length);
}
/**
* 在新的数组中添加20个单词
*/
void _retireveData(){
Future.delayed(new Duration(seconds: 2)).then((e)=>{
//_word 是一个数组,因为默认有一个元素,所以这里减一没关系
_word.insertAll(_word.length-1,generateWordPairs().take(20).map((e) => e.asPascalCase).toList()),
//每次生成20个单词
//这里用到了 english_words: ^3.1.0这个框架,调用生成单词的函数
//生成完了20个单词之后就要更新界面了
setState(() {
//重新构建列表,这里不用做什么事,空的调用也会提示程序刷新builder
})
});
}
}
class MyListView3 extends StatelessWidget{
@override
Widget build(BuildContext context) {
Widget divider1 = new Divider(color: Colors.red);
Widget divider2 = new Divider(color: Colors.blue);
// TODO: implement build
return MaterialApp(
title: "listView",
home: Scaffold(
appBar: AppBar(
title: Text("LsitView"),
),
body: ListView.separated(
itemBuilder: (BuildContext context, int index){
return ListTile(
title: Text("idnex$index"),
);
},
separatorBuilder:(BuildContext context, int index){
return index%2==0?divider1:divider2;
},
itemCount: 100),
),
);
}
}
class MyListView extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "ListViewText",
home: Scaffold(
appBar: AppBar(
title: Text("ListViewText"),
),
body: ListView.builder(
itemCount: 100,
itemExtent: 50,
itemBuilder: (BuildContext contxt,int index){
return ListTile(
title: Text("index$index"),
);
}
),
),
);
}
}
class SingleChildScrollViewTestRoute extends StatelessWidget{
@override
Widget build(BuildContext context) {
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
title: "测试",
home: Scaffold(
appBar: AppBar(
title: Text("SingleChildScrollViewTestRoute"),
),
body: SingleChildScrollView(
padding: EdgeInsets.all(16.0),
child: Center(
child: Column(
//动态的创建一个List<Widget>
children: str.split("").map((e)=>Text(e,textScaleFactor: 2.0,)).toList(),
),
),
),
),
);
}
}
class ScaffoldRoute extends StatefulWidget {
@override
_ScaffoldRoute createState() {
// TODO: implement createState
return _ScaffoldRoute();
}
}
class _ScaffoldRoute extends State<ScaffoldRoute> with SingleTickerProviderStateMixin{
List tabs = ["新闻", "历史", "图片"];
TabController _tabController;
int _selectedIndex = 1;
@override
void initState() {
// TODO: implement initState
// 创建Controller
_tabController = TabController(length: tabs.length, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "pro",
home: Scaffold(
appBar: AppBar(
//导航栏
title: Text("App Name"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
onPressed: () {
print("点击了");
},
),
],
bottom: TabBar(
controller: _tabController,
tabs: tabs.map((e)=>Tab(text: e,)).toList(),
),
),
drawer: MyDrawer(),
body:TabBarView(
controller: _tabController,
children:tabs.map((e){
return Container(
alignment: Alignment.center,
child: Text(e, textScaleFactor: 5),
);
}).toList()
),
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(icon: Icon(Icons.business), title: Text('Business')),
BottomNavigationBarItem(icon: Icon(Icons.school), title: Text('School')),
],
currentIndex: _selectedIndex,
//这个属性表示的是点击后的颜色变化
fixedColor: Colors.blue,
onTap: _onItemTapped,
),
),
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
}
class MyDrawer extends StatelessWidget {
const MyDrawer({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Drawer(
child: MediaQuery.removePadding(context: context,
child:Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 28.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ClipOval(
child: Image.network("https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=5ce3474036adcbef15397654cdc645b8/b7fd5266d01609242759dc9fd30735fae6cd3431.jpg",
width: 80,
),
),
),
Text("Wendux",
style: TextStyle(fontWeight: FontWeight.bold),
)
],
),
),
Expanded(
child: ListView(
children: <Widget>[
ListTile(
leading: const Icon(Icons.add),
title: const Text("add account"),
),
ListTile(
leading: const Icon(Icons.settings),
title: const Text("Manage account"),
),
],
),
),
],
)
)
);
}
}
class FlexLayoutTestRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "test",
home: Scaffold(
appBar: AppBar(
title: Text("test"),
),
body: MyLayoutTest(),
),
);
}
}
class MyLayoutTest extends StatelessWidget {
Widget redBox = DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
);
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "Test",
home: Scaffold(
appBar: AppBar(
title: Text("布局测试"),
),
body: Container(
//容器外补白
margin: EdgeInsets.only(top: 50.0, left: 120.0),
//容器的大小
constraints: BoxConstraints.tight(Size(500, 500)),
decoration: BoxDecoration(
//背景装饰
gradient: RadialGradient(
colors: [Colors.red, Colors.orange],
center: Alignment.topLeft,
radius: 0.98),
boxShadow: [
BoxShadow(
color: Colors.black54,
offset: Offset(2.0, 2.0),
blurRadius: 4.0),
],
),
//卡片倾斜式变换
transform: Matrix4.rotationZ(0.2),
//卡片内的文字居中
alignment: Alignment.center,
child: Text(
"薇薇一笑很倾城",
style: TextStyle(color: Colors.white, fontSize: 40.0),
),
),
),
);
}
}
class PaddingTestRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
//上下左右各添加16像素补白
padding: EdgeInsets.all(16.0),
child: Column(
//显式指定对齐方式为左对齐,排除对齐干扰
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
//左边添加8像素补白
padding: const EdgeInsets.only(left: 28.0),
child: Text("Hello world"),
),
Padding(
//上下各添加8像素补白
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text("I am Jack"),
),
Padding(
// 分别指定四个方向的补白
padding: const EdgeInsets.fromLTRB(20.0, .0, 20.0, 20.0),
child: Text("Your friend"),
)
],
),
);
}
}