gpt4 book ai didi

flutter 。 PageView 内的嵌套滚动

转载 作者:行者123 更新时间:2023-12-04 13:17:20 38 4
gpt4 key购买 nike

我有带有 PageView 小部件的简单页面,里面有 ListView。滚动 PageView 将不起作用。原因很简单。因为指针事件被嵌套的 child 消耗了。

  @override
Widget build(BuildContext context) {
setupController();

return PageView(
controller: controllerPage,
scrollDirection: Axis.vertical,
children: <Widget>[
ListView.builder(
controller: controller,
padding: EdgeInsets.all(AppDimens.bounds),
itemCount: 15,
itemBuilder: (context, index){
return Container(
height: 100,
color: index %2 == 0
? Colors.amber : Colors.blueAccent,
);
},
),
Container(color: Colors.green),
Container(color: Colors.blue),
],
);
}

我的问题是有什么合理的方法可以让它协同工作吗?您可能会看到 PageView 的垂直轴,但使用水平轴会出现完全相同的问题PageView 和水平 ListView 的组合。

到目前为止我尝试了什么?我有一些解决方法。即使它并不复杂,它只是感觉不太好和笨重。通过使用 AbsorbPointer 和自定义 Controller 进行滚动。

  final controller = ScrollController();
final controllerPage = PageController(keepPage: true);
bool hasNestedScroll = true;

void setupController() {
controller.addListener(() {

if (controller.offset + 5 > controller.position.maxScrollExtent &&
!controller.position.outOfRange) {
/// Swap to Inactive, if it was not
if (hasNestedScroll) {
setState(() {
hasNestedScroll = false;
});
}
} else {
/// Swap to Active, if it was not
if (!hasNestedScroll) {
setState(() {
hasNestedScroll = true;
});
}
}
});

controllerPage.addListener(() {
if (controllerPage.page == 0) {
setState(() {
hasNestedScroll = true;
});
}
});
}

@override
Widget build(BuildContext context) {
setupController();

return PageView(
controller: controllerPage,
scrollDirection: Axis.vertical,
children: <Widget>[
AbsorbPointer(
absorbing: !hasNestedScroll,
child: ListView.builder(
controller: controller,
padding: EdgeInsets.all(AppDimens.bounds),
itemCount: 15,
itemBuilder: (context, index){
return Container(
height: 100,
color: index %2 == 0
? Colors.amber : Colors.blueAccent,
);
},
),
),
Container(color: Colors.green),
Container(color: Colors.blue),
],
);
}

最佳答案

我最近遇到了类似的情况,在研究并阅读了 Flutter 中手势的工作原理后,我找到了一个足够好的工作解决方案。因此,我使用了 RawGestureDetector,它为您提供了手势的低级小部件处理,并通过将它们的 physics 设置为 NeverScrollableScrollPhysics 禁用了 PageView 和 ListView 的滚动。这意味着使用它们各自的 Controller 滚动这些小部件 - PageViewControllerScrollController。现在根据 ListView 的位置和状态,选择两者中的事件 Controller 并使用 Controller 拖动。主类看起来像这样。

void main() => runApp(App());

class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(appBar: AppBar(), body: NestedContainerWidget()));
}
}

class NestedContainerWidget extends StatefulWidget {
@override
_NestedContainerWidgetState createState() => _NestedContainerWidgetState();
}

class _NestedContainerWidgetState extends State<NestedContainerWidget> {
PageController _pageController;
ScrollController _listScrollController;
ScrollController _activeScrollController;
Drag _drag;

@override
void initState() {
super.initState();
_pageController = PageController();
_listScrollController = ScrollController();
}

@override
void dispose() {
_pageController.dispose();
_listScrollController.dispose();
super.dispose();
}

void _handleDragStart(DragStartDetails details) {
if (_listScrollController.hasClients &&
_listScrollController.position.context.storageContext != null) {
final RenderBox renderBox =
_listScrollController.position.context.storageContext.findRenderObject();
if (renderBox.paintBounds
.shift(renderBox.localToGlobal(Offset.zero))
.contains(details.globalPosition)) {
_activeScrollController = _listScrollController;
_drag = _activeScrollController.position.drag(details, _disposeDrag);
return;
}
}
_activeScrollController = _pageController;
_drag = _pageController.position.drag(details, _disposeDrag);
}

void _handleDragUpdate(DragUpdateDetails details) {
if (_activeScrollController == _listScrollController &&
details.primaryDelta < 0 &&
_activeScrollController.position.pixels ==
_activeScrollController.position.maxScrollExtent) {
_activeScrollController = _pageController;
_drag?.cancel();
_drag = _pageController.position.drag(
DragStartDetails(
globalPosition: details.globalPosition, localPosition: details.localPosition),
_disposeDrag);
}
_drag?.update(details);
}

void _handleDragEnd(DragEndDetails details) {
_drag?.end(details);
}

void _handleDragCancel() {
_drag?.cancel();
}

void _disposeDrag() {
_drag = null;
}

@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: <Type, GestureRecognizerFactory>{
VerticalDragGestureRecognizer:
GestureRecognizerFactoryWithHandlers<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer(), (VerticalDragGestureRecognizer instance) {
instance
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd
..onCancel = _handleDragCancel;
})
},
behavior: HitTestBehavior.opaque,
child: PageView(
controller: _pageController,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
children: [
Center(child: Text('Page 1')),
ListView(
controller: _listScrollController,
physics: const NeverScrollableScrollPhysics(),
children: List.generate(
20,
(int index) {
return ListTile(title: Text('Item $index'));
},
),
),
],
),
);
}
}

查看 _handleDragStart_handleDragUpdate 中的逻辑,它根据 ListView 小部件的状态确定应该滚动的 Controller ,它是滚动状态。

我写了一篇关于这个问题的详细文章,你可以在这里查看 - https://medium.com/@Mak95/nested-scrolling-listview-inside-pageview-in-flutter-a57b7a6241b1

解决方案可以改进,因此非常欢迎提供意见。

关于 flutter 。 PageView 内的嵌套滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59165110/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com