在 ListView 中,向下滚动时,在颤动中丢失数据
Posted
技术标签:
【中文标题】在 ListView 中,向下滚动时,在颤动中丢失数据【英文标题】:In ListView, on scrolling down, loosing data in flutter 【发布时间】:2020-12-30 12:44:02 【问题描述】:我有一种情况,我需要在滚动时维护自定义小部件的列表视图的状态。
以下是功能。
我有一个列表视图,每个列表视图都包含一个文本字段。在每个 ListView 项中,都有一个与每个项关联的嵌套列表,它是另一个 TextField。
ListView 和嵌套的 ListView 是动态创建的。但是在滚动到最后时,文本字段中的文本(父列表视图小部件和子列表视图小部件)被清除并且不保持状态。
以下是我的代码。
import 'package:flutter/material.dart';
void main()
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: NewCourse()));
class NewCourse extends StatefulWidget
@override
_NewCourseState createState() => _NewCourseState();
class _NewCourseState extends State<NewCourse>
bool isTagSelected = false;
bool isTopicCreationEnabled = false;
List<NewTopic> newTopicList = [];
addNewTopic()
newTopicList.add(new NewTopic());
setState(() );
enableTopicCreation(String txtTopicName)
setState(()
if (txtTopicName.length > 0)
isTopicCreationEnabled = true;
else
isTopicCreationEnabled = false;
);
@override
Widget build(BuildContext context)
var _createNewTopic;
if (isTopicCreationEnabled)
_createNewTopic = ()
addNewTopic();
;
else
_createNewTopic = null;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueGrey,
title: Text('ALL COURSES'),
centerTitle: true,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
color: Colors.blueGrey,
child: Center(
child: Padding(
padding: EdgeInsets.all(20),
child: Text(
"NEW COURSE",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
fontFamily: 'CodeFont',
color: Colors.white,
),
),
),
),
),
Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 20.0,
offset: Offset(0, 10),
),
],
),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 9,
child: Container(
padding: EdgeInsets.all(8),
margin: EdgeInsets.all(8),
child: TextField(
onChanged: (text)
enableTopicCreation(text);
,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Course Name",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
),
Expanded(
flex: 3,
child: FlatButton(
onPressed: _createNewTopic,
child: Container(
padding: EdgeInsets.all(18),
margin: EdgeInsets.all(8),
child: Icon(
Icons.add_box,
color: isTopicCreationEnabled
? Colors.green
: Colors.blueGrey,
),
),
),
),
],
),
],
),
),
Container(
child: Expanded(
child: getAllTopicsListView(),
),
),
],
),
);
Widget getAllTopicsListView()
ListView topicList = new ListView.builder(
shrinkWrap: true,
itemCount: newTopicList.length,
itemBuilder: (context, index)
return new ListTile(
title: new NewTopic(),
);
);
return topicList;
class NewTopic extends StatefulWidget
@override
_NewTopicState createState() => _NewTopicState();
class _NewTopicState extends State<NewTopic>
TextEditingController _topicController;
@override
void initState()
super.initState();
_topicController = new TextEditingController();
@override
void dispose()
super.dispose();
_topicController.dispose();
bool isSubTopicCreationEnabled = false;
List<NewSubTopic> newSubTopicList = [];
addNewSubTopic()
setState(()
newSubTopicList.add(new NewSubTopic());
);
enableSubTopicCreation(String txtTopicName)
setState(
()
if (txtTopicName.length > 0)
isSubTopicCreationEnabled = true;
else
isSubTopicCreationEnabled = false;
,
);
@override
Widget build(BuildContext context)
var _createNewSubTopic;
if (isSubTopicCreationEnabled)
_createNewSubTopic = ()
addNewSubTopic();
;
else
_createNewSubTopic = null;
return Column(
children: [
Container(
margin: EdgeInsets.only(top: 20, bottom: 20, left: 10, right: 50),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 20.0,
offset: Offset(0, 10),
),
],
),
child: Center(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 9,
child: Container(
child: TextField(
controller: _topicController,
onChanged: (text)
enableSubTopicCreation(text);
,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter the topic",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
),
Expanded(
flex: 3,
child: FlatButton(
onPressed: _createNewSubTopic,
child: Container(
child: Icon(
Icons.add_box,
color: isSubTopicCreationEnabled
? Colors.green
: Colors.blueGrey,
),
),
),
),
],
),
Row(
children: <Widget>[
Container(
child: Expanded(
//child: Text("Hi There!"),
child: getAllSubTopicsListView(),
),
),
],
),
],
),
),
),
],
);
Widget getAllSubTopicsListView()
ListView subTopicList = new ListView.builder(
shrinkWrap: true,
itemCount: newSubTopicList.length,
itemBuilder: (context, index)
return new ListTile(
title: new NewSubTopic(),
);
,
);
return subTopicList;
class NewSubTopic extends StatefulWidget
@override
_NewSubTopicState createState() => _NewSubTopicState();
class _NewSubTopicState extends State<NewSubTopic>
TextEditingController _subtopicController;
@override
void initState()
super.initState();
_subtopicController = new TextEditingController();
@override
void dispose()
super.dispose();
_subtopicController.dispose();
@override
Widget build(BuildContext context)
return Column(
children: [
Container(
margin: EdgeInsets.only(top: 20, bottom: 20, left: 50, right: 10),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey[400],
blurRadius: 20.0,
offset: Offset(0, 10),
),
],
),
child: Center(
child: Container(
child: TextField(
controller: _subtopicController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter the sub topic",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
),
),
],
);
我已经使用 TextEditingController 来维护状态,但没有解决问题。
问题: 一旦我向下滚动并滚动回屏幕顶部,就无法保持状态。清除父子项中 TextField 小部件中输入的文本。任何建议将不胜感激,谢谢。
【问题讨论】:
发生这种情况是因为,当 ListView 的元素未显示在屏幕上时,颤振会删除它们。因此,您的文本控制器会被丢弃,留下一个空的 TextField。 我已经使用 TextEditingController 来设置状态,但它不起作用。那么可能的解决方案是什么? 我没有尝试过,但我认为您必须制作一个包含文本字段的自定义有状态小部件,以便您可以将值存储在状态变量中,即使控制器被处置您的 wigdet 仍将具有状态变量中的值。只需确保将关键参数传递给您的自定义小部件,以便颤振可以区分列表中的所有项目。 如果您的列表很小,您可以使用常规的 ListView 小部件,而不是构建器。常规的 afaik 不会执行任何性能改进,并且会保留所有正在处理的数据,即使它不在屏幕上 我可以使用常规的 ListView 小部件,但每次单击添加图标时都会创建动态 ListView。 【参考方案1】:添加这个
class _HomeHomeMadeListState extends State<HomeHomeMadeList> with AutomaticKeepAliveClientMixin class _HomeHomeMadeListState extends State<HomeHomeMadeList>
@override
bool get wantKeepAlive => true;
【讨论】:
【参考方案2】:我在开发我的一个应用程序时遇到了同样的问题。
我通过将ListView
替换为用SingleChildScrollView
包裹的Column
来解决此问题。
这是因为ListView
仅在屏幕上呈现可见项目。
因此,每当您向上滚动时,子小部件和其中的状态(数据)都会被破坏,并且必须重新运行应用程序才能检索状态。
【讨论】:
以上是关于在 ListView 中,向下滚动时,在颤动中丢失数据的主要内容,如果未能解决你的问题,请参考以下文章
如何在颤动中使我的文本与 listview.builder 一起滚动