提交 20814971 authored 作者: shixiaochen's avatar shixiaochen

1、修改BaseListWidget,调用下拉刷新时,禁止手动滚动列表操作(列表刷新时,增加透明遮罩,禁止滚动列表);

上级 eb945f84
......@@ -17,4 +17,6 @@
* 移除获取设备id的git依赖
* 升级dio版本 5.1.3
## 1.0.9
* 修改SearchAppBar样式,设置默认右边距15
\ No newline at end of file
* 修改SearchAppBar样式,设置默认右边距15
## 1.1.0
* 修改BaseListWidget,调用下拉刷新时,禁止手动滚动列表操作;
\ No newline at end of file
......@@ -15,13 +15,20 @@ class _BaseListWidgetTestState extends State<BaseListWidgetTest> {
@override
Widget build(BuildContext context) {
final themeData = Theme.of(context);
return MyScaffold(
title: 'BaseListWidget',
floatingActionButton: Row(children: [
TextButton(
onPressed: () {
controller.reload();
},
child: Text("下拉刷新"),
),
],),
body: BaseListWidget(
controller: controller,
requestData: (page, pageSize, success, error) async {
await Future.delayed(const Duration(seconds: 5));
await Future.delayed(const Duration(seconds: 1));
if (page == 1) {
success([
{"key": "1", "value": "1"},
......@@ -66,32 +73,32 @@ class _BaseListWidgetTestState extends State<BaseListWidgetTest> {
),
);
},
header: TaurusHeader(
skyColor: themeData.colorScheme.primary,
),
footer: ClassicFooter(
dragText: 'Pull to load'.tr,
armedText: 'Release ready'.tr,
readyText: 'Loading...'.tr,
processingText: 'Loading...'.tr,
processedText: 'Succeeded'.tr,
noMoreText: 'No more'.tr,
failedText: 'Failed'.tr,
messageText: 'Last updated at %T'.tr,
),
startLoadWidget: Container(
decoration: BoxDecoration(
color: themeData.colorScheme.primary,
borderRadius: BorderRadius.circular(10),
),
alignment: Alignment.center,
width: double.infinity,
height: 300,
// child: const RiveAnimation.asset(
// 'assets/rive/highway-truck.riv',
// fit: BoxFit.cover,
// ),
),
// header: TaurusHeader(
// skyColor: themeData.colorScheme.primary,
// ),
// footer: ClassicFooter(
// dragText: 'Pull to load'.tr,
// armedText: 'Release ready'.tr,
// readyText: 'Loading...'.tr,
// processingText: 'Loading...'.tr,
// processedText: 'Succeeded'.tr,
// noMoreText: 'No more'.tr,
// failedText: 'Failed'.tr,
// messageText: 'Last updated at %T'.tr,
// ),
// startLoadWidget: Container(
// decoration: BoxDecoration(
// color: themeData.colorScheme.primary,
// borderRadius: BorderRadius.circular(10),
// ),
// alignment: Alignment.center,
// width: double.infinity,
// height: 300,
// // child: const RiveAnimation.asset(
// // 'assets/rive/highway-truck.riv',
// // fit: BoxFit.cover,
// // ),
// ),
),
);
}
......
......@@ -51,68 +51,82 @@ class _BaseListWidgetState extends State<BaseListWidget> {
final List<dynamic> _dataList = [];
int _page = 1;
int _count = 0;
bool startLoadingFinish = false; // 首次进入loading加载完成标识
StateType stateType = StateType.loading; // 列表状态
bool _startLoadingFinish = false; // 首次进入loading加载完成标识
StateType _stateType = StateType.loading; // 列表状态
// 禁止手动触发滚动,处理刷新过程中禁止滚动列表操作
bool disallowScroll = false;
@override
void initState() {
super.initState();
_controller = widget.controller ?? BaseListController();
_controller._bind(this); // 绑定 BaseListWidget state
}
@override
Widget build(BuildContext context) {
final header = buildHeader();
final footer = buildFooter();
return EasyRefresh(
controller: _controller.c,
refreshOnStart: widget.refreshOnStart,
header: header,
footer: footer,
refreshOnStartHeader: BuilderHeader(
triggerOffset: 70,
clamping: true,
position: IndicatorPosition.above,
processedDuration: Duration.zero,
builder: (ctx, state) {
if (state.mode == IndicatorMode.inactive ||
state.mode == IndicatorMode.done) {
startLoadingFinish = true;
return const SizedBox();
}
return Container(
padding: const EdgeInsets.only(bottom: 100),
return Stack(
children: [
EasyRefresh(
controller: _controller.c,
refreshOnStart: widget.refreshOnStart,
header: header,
footer: footer,
refreshOnStartHeader: BuilderHeader(
triggerOffset: 70,
clamping: true,
position: IndicatorPosition.above,
processedDuration: Duration.zero,
builder: (ctx, state) {
if (state.mode == IndicatorMode.inactive ||
state.mode == IndicatorMode.done) {
_startLoadingFinish = true;
return const SizedBox();
}
return Container(
padding: const EdgeInsets.only(bottom: 100),
width: double.infinity,
height: state.viewportDimension,
alignment: Alignment.center,
child: widget.startLoadWidget ??
SpinKitFadingCircle(
color: Theme.of(context).primaryColor,
size: 30,
));
},
),
onRefresh: _onRefresh,
onLoad: widget.noMoreLoad ? null : _onLoad,
child: buildScrollView(),
),
// 列表刷新时,增加透明遮罩,禁止滚动列表
Visibility(
visible: disallowScroll,
child: Container(
color: Colors.transparent,
width: double.infinity,
height: state.viewportDimension,
alignment: Alignment.center,
child: widget.startLoadWidget ??
SpinKitFadingCircle(
color: Theme.of(context).primaryColor,
size: 30,
));
},
),
onRefresh: _onRefresh,
onLoad: widget.noMoreLoad ? null : _onLoad,
child: buildScrollView(),
height: double.infinity),
),
],
);
}
Widget buildScrollView() {
return CustomScrollView(
slivers: buildSlivers(),
);
return CustomScrollView(slivers: buildSlivers());
}
Future<void> _onRefresh() async {
stateType = StateType.loading;
disallowScroll = false; // 开始刷新-重置标志位
_stateType = StateType.loading;
_page = 1;
await widget.requestData(
_page, widget.pageSize, _requestSuccess, _requestError);
}
Future<void> _onLoad() async {
stateType = StateType.loading;
_stateType = StateType.loading;
_page++;
await widget.requestData(
_page, widget.pageSize, _requestSuccess, _requestError);
......@@ -140,14 +154,14 @@ class _BaseListWidgetState extends State<BaseListWidget> {
? IndicatorResult.noMore
: IndicatorResult.success);
}
stateType = isEmpty ? StateType.empty : StateType.success;
_stateType = isEmpty ? StateType.empty : StateType.success;
}
void _requestError(code, msg) {
if (!mounted) {
return;
}
stateType = StateType.error;
_stateType = StateType.error;
ToastUtil.showToast(msg);
setState(() {});
if (_page == 1) {
......@@ -211,27 +225,19 @@ class _BaseListWidgetState extends State<BaseListWidget> {
return _dataList[index];
}
// 刷新单个数据
void notifySingleItem(index, item) {
_dataList[index] = item;
if (mounted) {
setState(() {});
}
}
List<Widget> buildSlivers() {
final header = buildHeader();
final footer = buildFooter();
return [
if (header.position == IndicatorPosition.locator)
const HeaderLocator.sliver(),
if (isEmpty && startLoadingFinish)
if (isEmpty && _startLoadingFinish)
SliverFillViewport(
delegate: SliverChildBuilderDelegate(
(context, index) {
return widget.emptyWidget ??
StateLayout(
type: stateType,
type: _stateType,
emptyImg: "default_drawing_1",
errorImg: "default_drawing_5",
onRefresh: _controller.reload,
......@@ -262,6 +268,23 @@ class _BaseListWidgetState extends State<BaseListWidget> {
Widget buildItem(BuildContext context, int index, dynamic item) {
return widget.itemBuilder(context, index, item);
}
// 刷新单个数据
void notifySingleItem(index, item) {
_dataList[index] = item;
if (mounted) {
setState(() {});
}
}
// 禁止手动触发滚动
void setDisallowScroll() {
if (mounted) {
setState(() {
disallowScroll = true;
});
}
}
}
// 列表控制器
......@@ -269,6 +292,11 @@ class BaseListController {
late EasyRefreshController _controller;
_BaseListWidgetState? _listState; // listState
/// Binding with BaseListWidget state
void _bind(_BaseListWidgetState state) {
_listState = state;
}
BaseListController() {
_controller = EasyRefreshController(
controlFinishRefresh: true,
......@@ -290,6 +318,7 @@ class BaseListController {
// 重新加载数据
void reload() {
_listState?.setDisallowScroll(); // 禁止手动触发滚动
// force true 强制刷新,解决快速刷新只触发一次问题
_controller.callRefresh(force: true);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论