我想将 PageViews 嵌套在 Flutter 中,在 PageView 中的 Scaffold 中使用 PageView。在外部 PageView 中,我将有 Logo 和联系信息,以及辅助信息。作为一个 child ,我将有一个带有内部 PageView 和一个 BottomNavigationBar 作为主要用户交互屏幕的脚手架。这是我到目前为止的代码:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp>{
int index = 0;
final PageController pageController = PageController();
final Curve _curve = Curves.ease;
final Duration _duration = Duration(milliseconds: 300);
_navigateToPage(value){
pageController.animateToPage(
value,
duration: _duration,
curve: _curve
);
setState((){
index = value;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PageViewCeption',
home: PageView(
children: <Widget>[
Container(
color: Colors.blue,
),
Scaffold(
body: PageView(
controller: pageController,
onPageChanged: (page){
setState(() {
index = page;
});
},
children: <Widget>[
Container(
child: Center(
child: Text('1', style: TextStyle(color: Colors.white))
)
),
Container(
child: Center(
child: Text('2', style: TextStyle(color: Colors.white))
)
),
Container(
child: Center(
child: Text('3', style: TextStyle(color: Colors.white))
)
),
],
),
backgroundColor: Colors.green,
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: (value) =>_navigateToPage(value),
currentIndex: index,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.cake),
title: Text('1')
),
BottomNavigationBarItem(
icon: Icon(Icons.cake),
title: Text('2')
),
BottomNavigationBarItem(
icon: Icon(Icons.cake),
title: Text('3')
)
],
),
),
Container(
color: Colors.blue
)
],
),
);
}
}
结果如下:
问题是:当我在内部 PageView 中时,我无法在第一页上向左滚动或在内部 PageView 的最后一页上向右滚动。在 BottomNavigationBar 上滚动(滑动)返回外部 PageView 的唯一方法。
在 the docs我们在 Scroll Physics Class 的描述中发现了这一点:
For example, determines how the Scrollable will behave when the user reaches the maximum scroll extent or when the user stops scrolling.
但是我还没有想出一个解决方案。有什么想法吗?
更新 1
我在使用 CustomScrollPhysics 类方面取得了进展:
class CustomScrollPhysics extends ScrollPhysics{
final PageController _controller;
const CustomScrollPhysics(this._controller, {ScrollPhysics parent }) : super(parent: parent);
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(_controller, parent: buildParent(ancestor));
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
assert(() {
if (value == position.pixels) {
throw new FlutterError(
'$runtimeType.applyBoundaryConditions() was called redundantly.\n'
'The proposed new position, $value, is exactly equal to the current position of the '
'given ${position.runtimeType}, ${position.pixels}.\n'
'The applyBoundaryConditions method should only be called when the value is '
'going to actually change the pixels, otherwise it is redundant.\n'
'The physics object in question was:\n'
' $this\n'
'The position object in question was:\n'
' $position\n'
);
}
return true;
}());
if (value < position.pixels && position.pixels <= position.minScrollExtent){ // underscroll
_controller.jumpTo(position.viewportDimension + value);
return 0.0;
}
if (position.maxScrollExtent <= position.pixels && position.pixels < value) {// overscroll
_controller.jumpTo(position.viewportDimension + (value - position.viewportDimension*2));
return 0.0;
}
if (value < position.minScrollExtent && position.minScrollExtent < position.pixels) // hit top edge
return value - position.minScrollExtent;
if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < value) // hit bottom edge
return value - position.maxScrollExtent;
return 0.0;
}
}
这是对 ClampingScrollPhysics applyBoundaryConditions 的修改。它有点工作,但由于 pageSnapping 它真的是错误的。它发生了,因为根据 the docs :
Any active animation is canceled. If the user is currently scrolling, that action is canceled.
当操作被取消时,如果用户停止拖动屏幕,PageView 开始快速返回到 Scafold 页面,这会使事情变得困惑。关于在这种情况下如何避免页面捕捉或更好地实现的任何想法?
最佳答案
我能够在嵌套 PageView
上复制该问题.看来内部PageView
覆盖检测到的手势。这就解释了为什么我们无法导航到外部 PageView
的其他页面。 ,但 BottomNavigationBar
能够。此行为的更多细节在此 thread 中进行了解释。 .
作为一种解决方法,您可以使用单个 PageView 并隐藏 BottomNavigationBar
在外页上。我稍微修改了你的代码。
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
var index = 0;
final PageController pageController = PageController();
final Curve _curve = Curves.ease;
final Duration _duration = Duration(milliseconds: 300);
var isBottomBarVisible = false;
_navigateToPage(value) {
// When BottomNavigationBar button is clicked, navigate to assigned page
switch (value) {
case 0:
value = 1;
break;
case 1:
value = 2;
break;
case 2:
value = 3;
break;
}
pageController.animateToPage(value, duration: _duration, curve: _curve);
setState(() {
index = value;
});
}
// Set BottomNavigationBar indicator only on pages allowed
_getNavBarIndex(index) {
if (index <= 1)
return 0;
else if (index == 2)
return 1;
else if (index >= 3)
return 2;
else
return 0;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PageViewCeption',
home: Scaffold(
body: Container(
child: PageView(
controller: pageController,
onPageChanged: (page) {
setState(() {
// BottomNavigationBar only appears on page 1 to 3
isBottomBarVisible = page > 0 && page < 4;
print('page: $page bottom bar: $isBottomBarVisible');
index = page;
});
},
children: <Widget>[
Container(
color: Colors.red,
),
Container(
color: Colors.orange,
),
Container(
color: Colors.yellow,
),
Container(
color: Colors.green,
),
Container(color: Colors.lightBlue)
],
),
),
bottomNavigationBar: isBottomBarVisible // if true, generate BottomNavigationBar
? new BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: (value) => _navigateToPage(value),
currentIndex: _getNavBarIndex(index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.cake), label: '1'),
BottomNavigationBarItem(icon: Icon(Icons.cake), label: '2'),
BottomNavigationBarItem(icon: Icon(Icons.cake), label: '3')
],
)
//else, create an empty container to hide the BottomNavigationBar
: Container(
height: 0,
),
),
);
}
}
关于dart - 在 flutter 中嵌套页面 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51368505/