我需要一些有关如何使用PageView的建议。我有一个在线项目,该项目允许用户构建自定义表单,并根据其他问题的答案来隐藏或显示问题。移动项目允许用户填写这些表格。我一直在使用适用于此功能的PageView,但我一直在努力找出如何指示PageView的结尾。现在,它将允许滚动一直持续下去。
return PageView.builder(
controller: _controller,
onPageChanged: (int index) {
FocusScope.of(context).requestFocus(FocusNode());
},
itemBuilder: (BuildContext context, int index) {
if (index >= _form.controls.length) {
print("Returning null");
return null;
}
return FormControlFactory.createFormControl(
_form.controls[index], null);
},
);
由于我不确定直到表格末尾有多少个元素如何结束滚动?
更新:在我的示例中,我尝试返回null,但它仍会滚动到末尾。
更新:这是我目前所在的位置:
class _FormViewerControllerState extends State<FormViewerController> {
int _currentIndex = 0;
List<FormGroupController> _groups = List();
List<StreamSubscription> _subscriptions = List();
Map<int, FormControlController> _controllerMap = Map();
bool _hasVisibilityChanges = false;
@override
void initState() {
super.initState();
for (var i = 0; i < widget.form.controls.length; i++) {
var control = widget.form.controls[i];
if (control.component == ControlType.header) {
_groups.add(FormGroupController(
form: widget.form,
formResponses: widget.responses,
headerIndex: i));
}
}
_controllerMap[_currentIndex] = _getControl(_currentIndex);
_subscriptions.add(FormsEventBus()
.on<FormControlVisibilityChanging>()
.listen(_onControlVisibilityChanging));
_subscriptions.add(FormsEventBus()
.on<FormControlVisibilityChanged>()
.listen(_onControlVisibilityChanged));
}
@override
Widget build(BuildContext context) {
print("Building pageview, current index: $_currentIndex");
return PageView.builder(
controller: PageController(
initialPage: _currentIndex,
keepPage: true,
),
onPageChanged: (int index) {
print("Page changed: $index");
_currentIndex = index;
FocusScope.of(context).requestFocus(FocusNode());
},
itemBuilder: (BuildContext context, int index) {
print("Building $index");
_controllerMap[index] = _getControl(index);
return _controllerMap[index].widget;
},
itemCount: _groups
.map((g) => g.visibleControls)
.reduce((curr, next) => curr + next),
);
}
@override
void dispose() {
_subscriptions.forEach((sub) => sub.cancel());
_groups.forEach((g) => g.dispose());
super.dispose();
}
FormControlController _getControl(int index) {
for (var group in _groups) {
// We want to reduce the index so it can be local to group
if (index >= group.visibleControls) {
index -= group.visibleControls;
continue;
}
for (var instance in group.instances) {
// We want to reduce the index so it can be local to the instance
if (index >= instance.visibleControls) {
index -= instance.visibleControls;
continue;
}
return instance.controls.where((c) => c.visible).elementAt(index);
}
}
throw StateError("Weird, the current control doesn't exist");
}
int _getControlIndex(FormControlController control) {
var index = 0;
for (var group in _groups) {
if (control.groupInstance.group.groupId != group.groupId) {
index += group.visibleControls;
continue;
}
for (var instance in group.instances) {
if (control.groupInstance.groupInstanceId != instance.groupInstanceId) {
index += instance.visibleControls;
continue;
}
for (var c in instance.controls.where((c) => c.visible)) {
if (c.control.id != control.control.id) {
index++;
continue;
}
return index;
}
}
}
throw StateError("Weird, can't find the control's index");
}
_onControlVisibilityChanging(FormControlVisibilityChanging notification) {
_hasVisibilityChanges = true;
}
_onControlVisibilityChanged(FormControlVisibilityChanged notification) {
if (!_hasVisibilityChanges) {
return;
}
setState(() {
print("Setting state");
var currentControl = _controllerMap[_currentIndex];
_controllerMap.clear();
_currentIndex = _getControlIndex(currentControl);
_controllerMap[_currentIndex] = currentControl;
});
_hasVisibilityChanges = false;
}
}
现在的问题是,如果更改导致在当前页面之前创建新页面,则为了保留在同一页面上,必须更改页面索引,以使其保留在当前页面上,而该部分不会工作。该构建方法被多次调用,由于某种原因最终显示原始索引。
有些示例打印语句显示了我的意思:
flutter: Control Text Box 2 (5) visible: true
flutter: Group instance Section 2 (1) visible controls: 1 -> 2
flutter: Group 1 clearing visible controls count
flutter: Setting state
flutter: Building pageview, current index: 2
flutter: Building 1
flutter: Building 2
flutter: Building pageview, current index: 2
flutter: Building 1
所以我一开始就在索引1上。我在该视图上选择要在索引1之前插入新页面的内容,因此是一个新索引1。我调用set state将当前索引设置为2,因为那是当前视图的新索引。如您所见,小部件中的build方法被调用两次,第一个方法在页面视图中呈现索引1和2,但是下一个方法即使初始索引设置为2也仅呈现索引1。
答案 0 :(得分:0)
由于我无法运行您发布的最小复制。我试图从示例应用程序本地复制行为。根据我的测试,在itemBuilder上返回null可以正常工作。我正在使用Flutter稳定频道1.22.0版
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
int pageViewIndex;
class _MyHomePageState extends State<MyHomePage> {
ActionMenu actionMenu;
final PageController pageController = PageController();
int currentPageIndex = 0;
int pageCount = 1;
@override
void initState() {
super.initState();
actionMenu = ActionMenu(this.addPageView, this.removePageView);
}
addPageView() {
setState(() {
pageCount++;
});
}
removePageView(BuildContext context) {
if (pageCount > 1)
setState(() {
pageCount--;
});
else
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Last page"),
));
}
navigateToPage(int index) {
pageController.animateToPage(
index,
duration: Duration(milliseconds: 300),
curve: Curves.ease,
);
}
getCurrentPage(int page) {
pageViewIndex = page;
}
createPage(int page) {
return Container(
child: Center(
child: Text('Page $page'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
actionMenu,
],
),
body: Container(
child: PageView.builder(
controller: pageController,
onPageChanged: getCurrentPage,
// itemCount: pageCount,
itemBuilder: (context, position) {
if (position == 5) return null;
return createPage(position + 1);
},
),
),
);
}
}
enum MenuOptions { addPageAtEnd, deletePageCurrent }
List<Widget> listPageView = List();
class ActionMenu extends StatelessWidget {
final Function addPageView, removePageView;
ActionMenu(this.addPageView, this.removePageView);
@override
Widget build(BuildContext context) {
return PopupMenuButton<MenuOptions>(
onSelected: (MenuOptions value) {
switch (value) {
case MenuOptions.addPageAtEnd:
this.addPageView();
break;
case MenuOptions.deletePageCurrent:
this.removePageView(context);
break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
PopupMenuItem<MenuOptions>(
value: MenuOptions.addPageAtEnd,
child: const Text('Add Page at End'),
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.deletePageCurrent,
child: Text('Delete Current Page'),
),
],
);
}
}
示例应用的外观如下。