在上一篇中,咱們學習了controller
、點擊事件onPressed
和GestureDetector
、TabBar
和PageView
聯動的使用,這一篇,咱們來講說ListView
的上拉刷新、下拉加載和輪播圖。java
官方爲咱們提供了RefreshIndicator
,主要有color
、backgroundColor
、displacement
、onRefresh
等屬性git
RefreshIndicator(
//刷新進度條顏色
color: Colors.black45,
//背景色
backgroundColor: Colors.blue,
//觸發下拉刷新的距離 默認40
displacement: 40,
//下拉回調方法,方法須要有async和await關鍵字,沒有await,刷新圖標立馬消失,沒有async,刷新圖標不會消失
onRefresh: refresh,
child: ListView.separated(
itemBuilder: ((context, index) {
return MoveItem();
}),
separatorBuilder: (context, index) {
return Divider(
color: Colors.black45,
height: 10,
);
},
itemCount: count,
),
),
複製代碼
int count = 2;
Future refresh() async {
await Future.delayed(Duration(seconds: 3), () {
setState(() {
count = 10;
});
});
}
複製代碼
效果圖以下 github
上拉加載的話,須要使用ListView
的controller
屬性app
final ScrollController _scrollController = new ScrollController();
@override
void initState() {
///增長滑動監聽
_scrollController.addListener(() {
///判斷當前滑動位置是否是到達底部,觸發加載更多回調
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
setState(() {
count += 5;
});
}
});
super.initState();
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
複製代碼
而後將_scrollController
設置給ListView
async
當咱們運行時卻發現,不只不能上拉加載,連下拉刷新也失效了!ide
這是由於,RefreshIndicator
和ScrollController
有兼容性問題,固然官方也給出瞭解決辦法,給ListView
添加以下代碼: physics: const AlwaysScrollableScrollPhysics()
oop
效果圖以下 學習
雖說功能實現了,可是感受效果有點怪怪的,新的item出現前應該有個過渡。 思路以下,當觸發上拉加載時,給ListView
添加一個加載中的item,當加載完成後,再移除。 先定義個變量,bool loadMore = false;
當觸發上拉加載時,設置爲true
動畫
@override
void initState() {
///增長滑動監聽
_scrollController.addListener(() {
///判斷當前滑動位置是否是到達底部,觸發加載更多回調
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
setState(() {
loadMore = true;
});
getMore();
}
});
super.initState();
}
複製代碼
加載完成時,設置爲false
ui
Future getMore() async {
await Future.delayed(Duration(seconds: 3), () {
setState(() {
loadMore = false;
count += 5;
});
});
}
複製代碼
這時,item就不能是固定的了
Widget getItem(int index) {
if (loadMore && index == count) {
return LoadMoreItem();
} else {
return MoveItem();
}
}
複製代碼
包括count
int getItemCount() {
if (loadMore) {
return count + 1;
} else {
return count;
}
}
複製代碼
效果圖以下
完整代碼以下
class ListViewDemo extends StatefulWidget {
@override
_ReListViewDemoState createState() => _ReListViewDemoState();
}
class _ReListViewDemoState extends State<ListViewDemo> {
int count = 2;
final ScrollController _scrollController = new ScrollController();
bool loadMore = false;
Future refresh() async {
await Future.delayed(Duration(seconds: 3), () {
setState(() {
count = 10;
});
});
}
Future getMore() async {
await Future.delayed(Duration(seconds: 3), () {
setState(() {
loadMore = false;
count += 5;
});
});
}
@override
void initState() {
///增長滑動監聽
_scrollController.addListener(() {
///判斷當前滑動位置是否是到達底部,觸發加載更多回調
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
setState(() {
loadMore = true;
});
getMore();
}
});
super.initState();
}
Widget getItem(int index) {
if (loadMore && index == count) {
return LoadMoreItem();
} else {
return MoveItem();
}
}
int getItemCount() {
if (loadMore) {
return count + 1;
} else {
return count;
}
}
@override
void dispose() {
super.dispose();
_scrollController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ListViewDemo'),
centerTitle: true,
brightness: Brightness.dark,
),
body: RefreshIndicator(
//刷新進度條顏色
color: Colors.black45,
//背景色
backgroundColor: Colors.blue,
////觸發下拉刷新的距離 默認40
displacement: 40,
//下拉回調方法,方法須要有async和await關鍵字,沒有await,刷新圖標立馬消失,沒有async,刷新圖標不會消失
onRefresh: refresh,
child: ListView.separated(
itemBuilder: ((context, index) {
return getItem(index);
}),
separatorBuilder: (context, index) {
return Divider(
color: Colors.black45,
height: 10,
);
},
itemCount: getItemCount(),
controller: _scrollController,
//保持ListView任何狀況都能滾動,解決在RefreshIndicator的兼容問題。
physics: const AlwaysScrollableScrollPhysics(), ), ), );
}
}
複製代碼
首先,用到的是PageView
,以及PageController
,這些以前已經說過,就不在細說
Widget _pageView() {
return PageView(
children: <Widget>[
Image.network(
'http://img4.imgtn.bdimg.com/it/u=1621655683,865218969&fm=200&gp=0.jpg',
height: 150,
fit: BoxFit.fitWidth,
),
Image.network(
'http://img1.imgtn.bdimg.com/it/u=1901690610,3955011377&fm=200&gp=0.jpg',
height: 150,
fit: BoxFit.fitWidth,
),
Image.network(
'http://img3.imgtn.bdimg.com/it/u=1546158593,2358526642&fm=200&gp=0.jpg',
height: 150,
fit: BoxFit.fitWidth,
),
],
controller: pageController,
);
}
複製代碼
其次,須要一個定時器,別忘記取消
int count = 3;
int currentPosition = 0;
@override
void initState() {
super.initState();
_timer = new Timer.periodic(Duration(seconds: 2), (time) {
//每2秒執行一次
changePage();
});
}
@override
void dispose() {
super.dispose();
_timer.cancel();
pageController.dispose();
}
void changePage() {
pageController.animateToPage(currentPosition % count,
duration: Duration(milliseconds: 200), curve: Curves.fastOutSlowIn);
currentPosition++;
}
複製代碼
效果圖以下
當咱們手動滑動時,currentPosition
會錯亂,咱們須要對其進行調整,須要用到的是onPageChanged
屬性
onPageChanged: (index) {
_timer.cancel();
currentPosition = index;
_timer = new Timer.periodic(Duration(seconds: 2), (time) {
changePage();
});
},
複製代碼
固然,這麼經常使用的控件,已經有造好的輪子了 flutter_swiper
首先添加依賴flutter_swiper: ^1.1.6
下面是一些經常使用屬性
Widget _swiper() {
return new Swiper(
itemBuilder: (BuildContext context, int index) {
return new Image.network(
"http://img4.imgtn.bdimg.com/it/u=1621655683,865218969&fm=200&gp=0.jpg",
fit: BoxFit.fitWidth,
height: 150,
);
},
itemCount: 3,
//動畫時間,默認300.0毫秒
duration: 300,
//初始位置
index: 0,
//無限輪播模式開關
loop: true,
//是否自動播放,默認false
autoplay: true,
layout: SwiperLayout.DEFAULT,
//滾動方式
scrollDirection: Axis.horizontal,
//點擊輪播的事件
onTap: (index) {},
//用戶拖拽的時候,是否中止自動播放
autoplayDisableOnInteraction: true,
//指示器
pagination: new SwiperPagination(),
//左右箭頭
control: null,
);
}
複製代碼