Как настроить пользовательский Listview вместе с настраиваемым редактируемым дочерним ListView в Flutter?

#flutter #expandablelistview #flutter-web

#flutter #расширяемый список просмотра #flutter-web

Вопрос:

У меня есть функциональность для реализации, где мне нужно настроить пользовательский список просмотра каждого виджета, содержащего текстовое поле и кнопку. И дочерний виджет содержит список каждого виджета, содержащий текстовое поле для ввода нового курса.

Обзор

Ниже приведена функциональность.

  1. Шаг 1 — это статическое поле для входа в курс.
  2. После ввода курса нажатие на кнопку добавить в поле курс добавит список просмотра динамического виджета (родительский список просмотра) любой темы.
  3. После загрузки виджета темы, нажав на правую кнопку добавить, необходимо добавить дочерний listview другого динамического виджета к родительскому (дочернему listview) подтем.
  4. Итак, на рисунке выше 2, 4 являются родительскими listviews, а 3, 5 должны быть дочерними listviews

Ниже приведен мой код.

 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
  

Любая помощь / предложение будут высоко оценены.
Заранее спасибо.

Ответ №1:

Вам просто нужно сжать ListViews:

         ListView topicList = new ListView.builder(
          shrinkWrap: true,
          itemCount: newTopicList.length,
        //...
        ListView subTopicList = new ListView.builder(
          shrinkWrap: true,
          itemCount: newSubTopicList.length,
  

ListView — это, по сути, CustomScrollView с одним SliverList в
его свойство CustomScrollView.slivers.

Если вид прокрутки не сжимается, то вид прокрутки расширится до максимально допустимого размера в scrollDirection. Если вид прокрутки имеет неограниченные ограничения в scrollDirection, то shrinkWrap должно быть true.

Вы можете узнать больше о ListView и shrinkWrap в официальном документе.