flutter - 如何在 Flutter 中配置自定义 Listview 以及自定义可编辑子 ListView?
问题描述
我有一个要实现的功能,我需要为每个包含 TextField 和按钮的小部件配置一个自定义列表视图。并且子小部件包含每个小部件的列表视图,其中包含一个用于进入新课程的 TextField。
以下是功能。
- 第 1 步是进入课程的静态字段。
- 进入课程后,点击课程字段中的添加按钮将添加任意主题的动态小部件(父列表视图)的ListView。
- 加载主题小部件后,单击右侧的添加按钮需要将另一个动态小部件的子列表视图附加到子主题的父(子列表视图)。
- 所以,在上图中,2, 4 是父列表视图,3, 5 需要是子列表视图
以下是我的代码。
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(
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> {
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(
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(
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> {
@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(
decoration: InputDecoration(
border: InputBorder.none,
hintText: "Enter the sub topic",
hintStyle: TextStyle(color: Colors.grey[400]),
),
),
),
),
),
],
);
}
}
这是问题
Assertion failed: file:///C:/src/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart:545:12
child.hasSize
is not true
任何帮助/建议将不胜感激。提前致谢。
解决方案
你只需要收缩 ListViews:
ListView topicList = new ListView.builder(
shrinkWrap: true,
itemCount: newTopicList.length,
//...
ListView subTopicList = new ListView.builder(
shrinkWrap: true,
itemCount: newSubTopicList.length,
ListView 基本上是一个 CustomScrollView,在其 CustomScrollView.slivers 属性中有一个 SliverList。
如果滚动视图不收缩包裹,那么滚动视图将扩展到滚动方向中允许的最大大小。如果滚动视图在scrollDirection 中有无限约束,则shrinkWrap 必须为真。
您可以在官方文档中了解更多关于ListView和shrinkWrap的信息。
推荐阅读
- tensorflow - 张量板中的不透明度图是什么?
- css - div 后面的下拉菜单显示 - z-index、溢出、位置不起作用
- json - 如何使用 terraform 云 API 调用传递数组和地图
- object - Rust:从同一个 Vec 的另一个对象修改为 Vec 中包含的一个对象
- javascript - 覆盖 React 中的常量文件值
- python - 如何根据来自另一个数据帧的条件从一个数据帧中检索单元格
- python - 在python中更改numpy数组的格式
- r - RJulia - 共享大型数据结构而不复制它们
- python - PyTorch - 在 NN 中有效地应用 TopK 梯度坐标
- node.js - 如何通过 puppeteer 拦截网站客户端生成的 blob 下载?