flutter - 在没有 setState Flutter 的情况下滚动时禁用 CustomScrollView 的滚动
问题描述
我有多个小部件和列表CustomScrollView
,我想CustomScrollView
在滚动某些像素绑定条件时停止滚动。
我可以用NeverScrollPhysics()
它来停止它,但我不想setState()
在这里使用函数,因为带有列表的 CustomScrollview 内容足够大,以至于在滚动时重新加载时屏幕会变得迟钝。
也尝试过,Provider
但构建器只提供了一个不与条子列表一起使用的子小部件。
这是使用的代码setState()
:
NotificationListener(
onNotification: (ScrollNotification notif) {
if(notif is ScrollUpdateNotification) {
if (canScroll && notif.metrics.pixels > 100) {
canScroll = false;
setState(() {});
}
}
if(notif is ScrollEndNotification) {
if(!canScroll) {
canScroll = true;
setState(() {});
}
}
return true;
},
child: CustomScrollView(
shrinkWrap: true,
physics: canScroll ? BouncingScrollPhysics() : NeverScrollableScrollPhysics(),
slivers: [
SliverToBoxAdapter(),
List(),
List(),
],
),
),
有没有办法只重新加载CustomScrollView
没有它的孩子?否则在这种情况下防止滚动的任何解决方法?
感谢帮助
解决方案
调用 build 方法时,该 build 方法中的所有小部件都将被重建,但小const
部件除外,但const
小部件不能接受动态参数(只能是常量值)。
Riverpod
在这种情况下提供了一个非常好的解决方案,ProviderScope
您可以通过inherited widget
而不是小部件构造函数传递参数(就像使用导航传递参数时一样),因此承包商可以const
.
例子 :
数据模块
TLDR 你需要使用Freezed
package 或覆盖== operator
并且hashCode
几乎总是因为 dart 问题。
class DataClass {
final int age;
final String name;
const DataClass(this.age, this.name);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DataClass && other.age == age && other.name == name;
}
@override
int get hashCode => age.hashCode ^ name.hashCode;
}
将我们设置ScopedProvider
为全局变量
final dataClassScope = ScopedProvider<DataClass>(null);
我们在列表中使用的小部件
class MyChildWidget extends ConsumerWidget {
const MyChildWidget();
@override
Widget build(BuildContext context, ScopedReader watch) {
final data = watch(dataClassScope);
// Note for better optimaization
// in case you are sure the data you are passing to this widget wouldn't change
// you can just use StatelessWidget and set the data as:
// final data = context.read(dataClassScope);
// use ConsumerWidget (or Consumer down in this child widget tree) if the data has to change
print('widget with name\n${data.name} rebuild');
return SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20),
child: Text(
'Name : ${data.name}\nAge ${data.age}',
textAlign: TextAlign.center,
),
),
);
}
}
最后是主要的CustomScrollView
小部件
class MyMainWidget extends StatefulWidget {
const MyMainWidget();
@override
State<MyMainWidget> createState() => _MyMainWidgetState();
}
class _MyMainWidgetState extends State<MyMainWidget> {
bool canScroll = true;
void changeCanScrollState() {
setState(() => canScroll = !canScroll);
print('canScroll $canScroll');
}
final dataList = List.generate(
20,
(index) => DataClass(10 * index, '$index'),
);
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
changeCanScrollState();
},
child: CustomScrollView(
shrinkWrap: true,
physics: canScroll
? BouncingScrollPhysics()
: NeverScrollableScrollPhysics(),
slivers: [
for (int i = 0; i < dataList.length; i++)
ProviderScope(
overrides: [
dataClassScope.overrideWithValue(dataList[i]),
],
child: const MyChildWidget(),
),
],
),
),
);
}
}
不要忘记包装MaterialApp
with ProviderScope
。
runApp(
ProviderScope(
child: MyApp(),
),
);
推荐阅读
- python - 将 csv 文件上传到 db2 时出现内存限制错误
- node.js - 在几个选项卡中的页面刷新时,并不总是在 expressjs 应用程序中设置 Cookie
- django - 从 django 直接在浏览器中设置 http only cookie(前端很苗条)
- python - 名称超过 75 个字符的 Django 电子邮件
- node.js - /node_modules/node/bin/node:windows中没有这样的文件或目录
- reactjs - onUpdate 的 Firestore 导航和随机播放数组
- php - 在只读文件系统中工作的 PHP Web 应用程序
- linux - 如何就地编辑 curl 输出?
- python - 从音频中提取 ivector
- javascript - 尝试在 Google Maps API 中实现“shouldFocus”infoWindowOpen 选项