Android Flutter實現(xiàn)自定義下拉刷新組件
前言
在Flutter開發(fā)中官方提供了多平臺的下拉刷新組件供開發(fā)者使用,例如RefreshIndicator和CupertinoSliverRefreshControl分別適配Android和iOS下拉刷新交互形態(tài)。但實際情況中這兩者使用情況卻不太相同在使用場景就存在差異,RefreshIndicator作為嵌套型下拉組件列表內(nèi)容作為它的child使用而CupertinoSliverRefreshControl是嵌入在Sliver列表中使用。同時對于交互設(shè)計來說一般更偏好RefreshIndicator下拉形式,通過下拉列表整體下移后透出拉下刷新組件樣式。
改造點
DIY下拉組件樣式
RefreshIndicator下拉組件樣式可能會在交互上不符合設(shè)計師要求。例如下拉過程中l(wèi)oading樣式出現(xiàn)交互是會和列表重合,實際需求可能是希望下拉過程中l(wèi)oading樣式和列表一樣同步下移出現(xiàn)。
因此修改原有的下拉刷新組件樣式構(gòu)建,構(gòu)建方法入?yún)⒅饕莚efreshState、pulledExtent、refreshTriggerPullDistance、refreshIndicatorExtent。原邏輯中組件偏量是固定不變_kActivityIndicatorMargin值,因此下拉組件樣式是直接顯示出來的。
調(diào)整方案根據(jù)pulledExtent下拉距離,默認偏移下拉組件樣式自身高度加上下拉距離從而將偏移量從負方向向正方向展示。
Widget buildRefreshIndicator(
BuildContext context,
RefreshIndicatorMode refreshState, //下拉狀態(tài)
double pulledExtent, // 下拉實時距離
double refreshTriggerPullDistance, // 下拉限制最大高度
double refreshIndicatorExtent, // 下拉組件最大高度
) {
return Container(
color: Colors.deepOrange,
child: Stack(
clipBehavior: Clip.none,
children: <Widget>[
Positioned(
top: -refreshIndicatorExtent + pulledExtent,
left: 0.0,
right: 0.0,
//簡易的下拉樣式 忽略refreshState狀態(tài)
child: Container(
child: Text("我是下拉呀~~~~",style: TextStyle(color: Colors.white,fontSize: 20,),textAlign: TextAlign.center,),
),
),
],
),
);
}刷新時機調(diào)整
RefreshIndicator下拉組件另外刷新觸發(fā)交互點也不是設(shè)計交互期望的邏輯,它的刷新觸發(fā)機制是只要下拉超過設(shè)置下拉距離并會觸發(fā)。但實際開發(fā)中可能并不希望當(dāng)?shù)竭_對應(yīng)點就去做刷新操作而是下拉到一定距離松手后才會觸發(fā),因此需要改造下拉刷新組件內(nèi)部的刷新機制。
原下拉刷新邏輯如下關(guān)鍵代碼所示,只要當(dāng)RefreshIndicatorMode.drag狀態(tài)下并且latestIndicatorBoxExtent > widget.refreshTriggerPullDistance時就會觸發(fā)下拉刷新方法。
RefreshIndicatorMode transitionNextState() {
RefreshIndicatorMode nextState;
。、、、 、、、 省略
drag:
case RefreshIndicatorMode.drag:
if (latestIndicatorBoxExtent == 0) {
return RefreshIndicatorMode.inactive;
} else if (latestIndicatorBoxExtent < widget.refreshTriggerPullDistance) {
return RefreshIndicatorMode.drag;
} else {
// 當(dāng)latestIndicatorBoxExtent > widget.refreshTriggerPullDistance就執(zhí)行
if (widget.onRefresh != null) { //刷新邏輯執(zhí)行點
HapticFeedback.mediumImpact();
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
refreshTask = widget.onRefresh()..whenComplete(() {
if (mounted) {
setState(() => refreshTask = null);
refreshState = transitionNextState();
}
});
setState(() => hasSliverLayoutExtent = true);
});
}
return RefreshIndicatorMode.armed;
}
break;
case RefreshIndicatorMode.armed:
if (refreshState == RefreshIndicatorMode.armed && refreshTask == null) {
goToDone();
continue done;
}
if (latestIndicatorBoxExtent > widget.refreshIndicatorExtent) {
return RefreshIndicatorMode.armed;
} else {
nextState = RefreshIndicatorMode.refresh;
}
continue refresh;
refresh:
case RefreshIndicatorMode.refresh:
if (refreshTask != null) {
return RefreshIndicatorMode.refresh;
} else {
goToDone();
}
continue done;
、、、、、省略
}
return nextState;
}弱希望下拉松手后判斷是否觸發(fā)刷新只修改RefreshIndicator下拉組件似乎無法直接滿足條件。因此需要結(jié)合手勢監(jiān)聽來完成,需要對整體框架代碼做一個調(diào)整。
增加Listener嵌套監(jiān)聽手勢抬起操作,獲取MagicSliverRefreshControlState(原是私有類放開為公有)判斷是否是超出下拉最小刷新間距,對內(nèi)部是否可刷新標(biāo)記進行賦值操作。
GlobalKey<MagicSliverRefreshControlState> key = GlobalKey<MagicSliverRefreshControlState>();
Listener(
child: CustomScrollView(
physics: BouncingScrollPhysics(),
slivers: <Widget>[
MagicSliverRefreshControl(
key: key,
builder: buildRefreshIndicator,
onRefresh: () async {
print("<> SliverRefreshControl onRefresh start");
await Future.delayed(Duration(seconds: 2),(){});
print("<> SliverRefreshControl onRefresh end");
},
),
SliverList(
delegate: SliverChildBuilderDelegate(
(content, index) {
return Common.getWidget(index);
},
childCount: 100,
),
)
],
),
onPointerUp: (event){ //判斷是否可刷新操作
if(key?.currentState?.isCanRefreshAction() ?? false){
key?.currentState?.canRefresh = true;
}else{
key?.currentState?.canRefresh = false;
}
},
);RefreshIndicator組件內(nèi)部增加一種新狀態(tài)RefreshIndicatorMode.over用來判斷是否刷新臨界狀態(tài),結(jié)合外部手勢抬手監(jiān)聽。當(dāng)下拉超出刷新最小間距且抬手放開判斷觸發(fā)刷新操作,over恢復(fù)到drag還是進入armed都是通過以上條件來實現(xiàn)的,其他原邏輯保持不變。
switch (refreshState) {
case RefreshIndicatorMode.inactive:
if (latestIndicatorBoxExtent <= 0) {
return RefreshIndicatorMode.inactive;
} else {
nextState = RefreshIndicatorMode.drag;
}
continue drag;
drag:
case RefreshIndicatorMode.drag:
if (latestIndicatorBoxExtent == 0) {
return RefreshIndicatorMode.inactive;
}
else if (latestIndicatorBoxExtent < widget.refreshTriggerPullDistance) {
return RefreshIndicatorMode.drag;
} else {
return RefreshIndicatorMode.over; //增加一種狀態(tài) 表示下拉滿足刷新條件
}
break;
/// 進入新狀態(tài)后結(jié)合抬手后是否可刷新標(biāo)記為判斷是進入刷新方法還是回到拖拽狀態(tài)
case RefreshIndicatorMode.over:
if (latestIndicatorBoxExtent <= widget.refreshTriggerPullDistance) {
if(canRefresh){
canRefresh = false; //將刷新標(biāo)記置空復(fù)位
if (widget.onRefresh != null) {
HapticFeedback.mediumImpact();
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
refreshTask = widget.onRefresh()..whenComplete(() {
if (mounted) {
setState(() => refreshTask = null);
refreshState = transitionNextState();
}
});
setState(() => hasSliverLayoutExtent = true);
});
}
return RefreshIndicatorMode.armed;
}else{
return RefreshIndicatorMode.drag;
}
}
return RefreshIndicatorMode.over;
break;效果展示
調(diào)整前

調(diào)整后

以上就是Android Flutter實現(xiàn)自定義下拉刷新組件的詳細內(nèi)容,更多關(guān)于Android Flutter下拉刷新的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android xml實現(xiàn)按鈕的圓角、陰影效果及按下變化效果的實現(xiàn)代碼
這篇文章主要介紹了android xml實現(xiàn)按鈕的圓角、陰影效果以及按下變化效果,通過五個xml文件實現(xiàn)按鈕的圓角陰影效果,代碼也很簡單,需要的朋友可以參考下2021-05-05
Android中新引進的Google Authenticator驗證系統(tǒng)工作原理淺析
這篇文章主要介紹了Android中新引進的Google Authenticator驗證系統(tǒng)工作原理淺析,需要的朋友可以參考下2014-10-10
Android?PowerManagerService?打開省電模式
這篇文章主要介紹了Android?PowerManagerService打開省電模式,文章通告省電模式的打開過程、什么是?battery?saver?sticky?模式兩部分展開詳情,感興趣的朋友可以參考一下2022-08-08
Android開發(fā)中使用sqlite實現(xiàn)新聞收藏和取消收藏的功能
本篇文章主要介紹了sqlite實現(xiàn)新聞收藏和取消收藏功能,主要涉及到oracle數(shù)據(jù)庫方面的內(nèi)容,對于Android開發(fā)sqlite實現(xiàn)收藏和取消功能感興趣的朋友可以參考下本文2016-11-11
Android?APN數(shù)據(jù)庫查詢對比分析(APN案例)
文章詳細介紹了Android中APN數(shù)據(jù)查詢的實現(xiàn)方式,文章說明了如何避免在主線程進行IO操作,從而提高應(yīng)用的響應(yīng)性和用戶體驗,感興趣的朋友一起看看吧2025-03-03
Android OkHttp 結(jié)合php 多圖片上傳實例
本篇文章主要介紹了Android OkHttp 結(jié)合php 多圖片上傳實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05
Android自定義Scrollbar的兩種實現(xiàn)方式
本文介紹兩種實現(xiàn)自定義滾動條的方法,分別通過ItemDecoration方案和獨立View方案實現(xiàn)滾動條定制化,文章通過代碼示例講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2025-03-03

