gpt4 book ai didi

flutter - 动态构建一个 Flutter PageView

转载 作者:行者123 更新时间:2023-12-03 19:31:33 25 4
gpt4 key购买 nike

我需要一些关于如何使用 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;
}
}

现在的问题是,如果更改导致在当前页面之前出现一个新页面,为了保持在同一页面上,页面索引必须更改以使其保持在当前页面上并且该部分不起作用。 build 方法被多次调用,最终由于某种原因显示原始索引。

这里有一些示例打印语句显示了我的意思:
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 上。我在该 View 上选择了一些导致在索引 1 之前插入新页面的内容,因此新索引为 1。我调用 set state 将当前索引设置为 2,因为这是当前 View 的新索引。如您所见,小部件中的 build 方法被调用两次,第一次在页面 View 中呈现索引 1 和 2,但即使初始索引设置为 2,下一次也仅呈现索引 1。

最佳答案

由于我无法运行您发布的最小重现。我试图从示例应用程序本地复制该行为。根据我的测试,在 itemBuilder 上返回 null 可以按预期工作。我正在使用 Flutter 稳定 channel 版本 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'),
),
],
);
}
}
这是示例应用程序的外观。
demo

关于flutter - 动态构建一个 Flutter PageView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53916692/

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