skip to Main Content

It is a bug of a ListView inside another ListView.

A simple Scaffold with the body showing a ListView (it doesn’t matter if it is a ListView or a ListView.builder, both will have the same behavior, therefore, the same bug.) with a Column widget that has two widgets inside: a StatefulWidget and another ListView.builder widget, and this ListView.builder widget inside the Column widget has a ListTile widget that only displays information: text with the index and a delete icon. While the StatefulWidget contains another ListView.builder.

The StatefulWidget gets "STUCK" in a specific position. Not a position in the list that controls the ListView widget, but in the layout itself, which is extremely bizarre. Even if you delete the Column widget that would have the StatefulWidget, it simply doesn’t disappear, it remains, regardless of whether you use const or not when calling the StatefulWidget.

I created a simple DartPad with only 150 lines of code, with the code that I will share with you below so that everyone can test it.

Change the Flutter version in DartPad (Main, Stable, Beta) and always the same behavior. I will not under any circumstances change the Flutter installed on my computer, as I have edits to the files that I need to keep for very specific projects of my clients.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ListViewWithDelete(),
    );
  }
}

class ListViewWithDelete extends StatefulWidget {
  @override
  _ListViewWithDeleteState createState() => _ListViewWithDeleteState();
}

class _ListViewWithDeleteState extends State<ListViewWithDelete> {
  List<String> items = List<String>.generate(10, (index) => 'Item ${index + 1}');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListView com Botão de Excluir'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                return Column(
                  children: [
                    AulaWidget(),
                    ListTile(
                      leading: IconButton(
                        icon: Icon(Icons.delete),
                        onPressed: () {
                          setState(() {
                            items.removeAt(index);
                          });
                        },
                      ),
                      title: Text(items[index]),
                    ),
                  ],
                );
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: ElevatedButton(
              onPressed: () {
                setState(() {
                  items.add('Item ${items.length + 1}');
                });
              },
              child: Text('Adicionar Item'),
            ),
          ),
        ],
      ),
    );
  }
}

class AulaWidget extends StatefulWidget {
  @override
  _AulaWidgetState createState() => _AulaWidgetState();
}

class _AulaWidgetState extends State<AulaWidget> {
  List<String> listaDeAulas = List<String>.generate(5, (index) => 'Aula $index');

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListView.builder(
          itemCount: listaDeAulas.length,
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemBuilder: (BuildContext context, int index) {
            return ListTile(
              leading: IconButton(
                icon: const Icon(Icons.delete),
                onPressed: () {
                  setState(() {
                    listaDeAulas.removeAt(index);
                  });
                },
              ),
              title: Text("Sinais de Trânsito ${listaDeAulas[index]}"),
            );
          },
        ),
        const SizedBox(height: 16),
        Row(
          children: [
            Expanded(
              child: ElevatedButton(
                onPressed: () {
                  setState(() {
                    listaDeAulas.add('Aula ${listaDeAulas.length}');
                  });
                },
                child: const Text('Adicionar Aula'),
              ),
            ),
          ],
        ),
      ],
    );
  }

  void _showConfirmationDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text("Adicionar Nova Aula"),
          content: const Text("Deseja adicionar uma nova aula?"),
          actions: <Widget>[
            TextButton(
              child: const Text("Cancelar"),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
            TextButton(
              child: const Text("Confirmar"),
              onPressed: () {
                setState(() {
                  listaDeAulas.add('Aula ${listaDeAulas.length}');
                });
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }
}

I realized that I was unable to correctly express the behavior of the code, since the responses I have received so far have only been about the list called listaDeAulas with some solutions that were not tested before being presented here in my post.

So I will kindly ask you in a very earnest manner to copy the code I provided and put it in DartPad. Do not make any changes to the code and do not worry about the Flutter versions. And then click on the button to add classes in a single item. Then try to delete the item that you just added classes to and notice that the classes that are part of, that are linked to, that specific item you wanted simply do not disappear, they remain fixed, including in the same position in the list.

I have already implemented the solutions provided so far: 09/20/2024 and none of them worked, because I believe I had not expressed myself better so that you would understand the importance of having observed the behavior of the code in DartPad, I hope I have been clear enough now.

Today 22.09.2024 I was able to find a solution.

Thanks to @pskink tireless efforts, I was finally able to resolve the issue. I’ll put the complete code here with the final solution so you can reproduce it via DartPad.

And a constructive criticism to those who downvoted my post: if you thought my post was not positive for the community, you are wrong, because what I proved in DartPad is in fact a bug and I will report it to the Flutter team to improve Flutter. When the solution is implemented by the Flutter team I will make sure to come back to this post to reference it, just to prove once and for all that you who downvoted my post are wrong.

The fullcode (still in development):

// Copyright 2019 the Dart project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
      ),
      home: const CriarCursoProfessorModulo(),
    );
  }
}

class CriarCursoProfessorModulo extends StatefulWidget {
  const CriarCursoProfessorModulo({super.key});

  @override
  State<CriarCursoProfessorModulo> createState() =>
      _CriarCursoProfessorModuloState();
}

class _CriarCursoProfessorModuloState extends State<CriarCursoProfessorModulo>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;
  bool _isExpanded = true;

  Map<ModuloModel, List<AulaModel>> listaDeModulosAulas = {};

  void _toggleExpansion() {
    setState(() {
      _isExpanded = !_isExpanded;
      if (_isExpanded) {
        _controller.reverse();
      } else {
        _controller.forward();
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
    _animation = Tween<double>(begin: 1, end: 0).animate(_controller);

    // Exemplo de módulo inicial
    ModuloModel moduloModel = ModuloModel(
      idModulo: "1",
      titulo: "Módulo 1",
      aulas: [],
      materialDeApoio: [],
      criadoem: DateTime.now(),
      atualizadoem: DateTime.now(),
    );

    listaDeModulosAulas.addAll({
      moduloModel: [],
    });
  }

  @override
  Widget build(BuildContext context) {
    bool lightMode =
        MediaQuery.of(context).platformBrightness == Brightness.light;

    return Scaffold(
      backgroundColor: lightMode ? Colors.white : Colors.white,
      body: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
          

          
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 24.0),
              child: Column(
                children: [
                TextButton.icon(
                        style: ButtonStyle(
                          backgroundColor: WidgetStateProperty.all<Color>(
                            const Color(0xff029846),
                          ),
                          shape: WidgetStateProperty.all(RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(4),
                          )),
                          padding: WidgetStateProperty.all<EdgeInsets>(
                            const EdgeInsets.only(
                              top: 10,
                              bottom: 10,
                              left: 16,
                              right: 16,
                            ),
                          ),
                        ),
                        onPressed: () {
                          ModuloModel moduloModel = ModuloModel(
                            idModulo: "",
                            titulo: "",
                            aulas: [],
                            materialDeApoio: [],
                            criadoem: DateTime.now(),
                            atualizadoem: DateTime.now(),
                          );

                          setState(() {
                            listaDeModulosAulas.addAll({
                              moduloModel: [],
                            });
                          });
                        },
                        icon: const Icon(
                          Icons.add,
                          color: Colors.white,
                        ),
                        label: const SizedBox(
                          child: Text(
                            "Novo módulo",
                            textAlign: TextAlign.center,
                            style: TextStyle(
                              fontSize: 15,
                              fontWeight: FontWeight.w900,
                              color: Color(0xffFFFFFF),
                            ),
                          ),
                        ),
                      ),
                  ListView.builder(
                    shrinkWrap: true,
                    itemCount: listaDeModulosAulas.length,
                    physics: const NeverScrollableScrollPhysics(),
                    itemBuilder: (BuildContext context, int index) {
                      ModuloModel modulo =
                          listaDeModulosAulas.keys.elementAt(index);
                      List<AulaModel> aulas =
                          listaDeModulosAulas.values.elementAt(index);
                      return Card(
                        elevation: 0.0,
                        color: Colors.white,
                        borderOnForeground: true,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(16.0),
                          side: const BorderSide(
                            color: Color(0xffA9A9A9),
                            width: 1,
                          ),
                        ),
                        child: Padding(
                          padding: const EdgeInsets.only(
                            left: 16.0,
                            right: 16.0,
                            top: 8,
                            bottom: 8,
                          ),
                          child: Column(
                            mainAxisSize: MainAxisSize
                                .min, // Permite que a Column encolha
                            children: [
                              Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  Text(
                                    modulo.titulo,
                                    style: const TextStyle(
                                      fontWeight: FontWeight.w500,
                                      fontSize: 16,
                                      color: Color(0xff404040),
                                    ),
                                  ),
                                  IconButton(
                                    onPressed: _toggleExpansion,
                                    icon: AnimatedSwitcher(
                                      duration:
                                          const Duration(milliseconds: 300),
                                      transitionBuilder: (Widget child,
                                          Animation<double> animation) {
                                        return FadeTransition(
                                          opacity: animation,
                                          child: ScaleTransition(
                                            scale: animation,
                                            child: child,
                                          ),
                                        );
                                      },
                                      child: _isExpanded
                                          ? const Icon(
                                              Icons.keyboard_arrow_up_outlined)
                                          : const Icon(Icons
                                              .keyboard_arrow_down_outlined),
                                    ),
                                  ),
                                ],
                              ),
                              SizeTransition(
                                // Anima o tamanho do botão
                                sizeFactor: _animation,
                                child: Column(
                                  children: [
                                    AulaWidget(
                                      aulas: aulas,
                                      aoMudarAula: (novasAulas) {
                                        setState(() {
                                          listaDeModulosAulas[modulo] =
                                              novasAulas;
                                        });
                                      },
                                    ),
                                    TextButton(
                                      style: ButtonStyle(
                                        backgroundColor:
                                            WidgetStateProperty.all<Color>(
                                          const Color(0xffF44336)
                                              .withOpacity(0.08),
                                        ),
                                        shape: WidgetStateProperty.all(
                                          RoundedRectangleBorder(
                                            borderRadius:
                                                BorderRadius.circular(12),
                                          ),
                                        ),
                                        padding:
                                            WidgetStateProperty.all<EdgeInsets>(
                                          const EdgeInsets.only(
                                            top: 13,
                                            bottom: 13,
                                            left: 28.5,
                                            right: 28.5,
                                          ),
                                        ),
                                      ),
                                      onPressed: () {
                                        setState(() {
                                          listaDeModulosAulas.remove(modulo);
                                        });
                                      },
                                      child: const SizedBox(
                                        width: double.infinity,
                                        child: Text(
                                          "Excluir módulo",
                                          textAlign: TextAlign.center,
                                          style: TextStyle(
                                            fontSize: 14,
                                            fontWeight: FontWeight.w900,
                                            color: Color(0xffF44336),
                                          ),
                                        ),
                                      ),
                                    ),
                                    const SizedBox(
                                      height: 16,
                                    ),
                                  ],
                                ),
                              ),
                            ],
                          ),
                        ),
                      );
                    },
                  ),
               
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class AulaWidget extends StatefulWidget {
  final List<AulaModel>? aulas;
  final ValueChanged<List<AulaModel>>? aoMudarAula;
  const AulaWidget({
    super.key,
    this.aulas,
    this.aoMudarAula,
  });

  @override
  State<AulaWidget> createState() => _AulaWidgetState();
}

class _AulaWidgetState extends State<AulaWidget> {
  final FocusScopeNode _focusScopeNode = FocusScopeNode();

  @override
  void dispose() {
    _focusScopeNode.dispose();
    super.dispose();
  }

  // Função para adicionar uma aula
  void _adicionarAula() {
    setState(() {
      widget.aulas!.add(AulaModel(
        idAula: "1",
        titulo: "Nova Aula",
        descricao: "",
        criadoem: DateTime.now(),
        atualizadoem: DateTime.now(),
      ));
      widget.aoMudarAula!(widget.aulas!);
    });
  }

  // Função para remover uma aula
  void _removerAula(int index) {
    setState(() {
      widget.aulas!.removeAt(index);
      widget.aoMudarAula!(widget.aulas!);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListView.builder(
          itemCount: widget.aulas!.length,
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          itemBuilder: (BuildContext context, int index) {
            AulaModel aulaModel = widget.aulas!.elementAt(index);
            return Container(
              decoration: BoxDecoration(
                color: const Color(0xffF6F6F6),
                borderRadius: BorderRadius.circular(4),
              ),
              padding: const EdgeInsets.only(
                top: 17,
                bottom: 17,
                right: 16,
                left: 16,
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Expanded(
                    child: Row(
                      children: [
                        const Icon(
                          Icons.play_circle,
                          color: Color(0xff2196F3),
                        ),
                        const SizedBox(
                          width: 8,
                        ),
                        Flexible(
                          child: Text(
                            aulaModel.titulo,
                            style: const TextStyle(
                              color: Color(0xff2196F3),
                              fontSize: 14,
                              fontWeight: FontWeight.w600,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  Row(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      IconButton(
                        onPressed: () {},
                        icon: const Icon(
                          Icons.edit,
                          color: Color(0xff2A2E45),
                        ),
                      ),
                      IconButton(
                        onPressed: () {
                          _removerAula(index);
                        },
                        icon: const Icon(
                          Icons.delete,
                          color: Color(0xffF44336),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            );
          },
        ),
        const SizedBox(
          height: 16,
        ),
        Row(
          children: [
            Expanded(
              child: TextButton(
                style: ButtonStyle(
                  backgroundColor: WidgetStateProperty.all<Color>(
                    const Color(0xff029846).withOpacity(0.08),
                  ),
                  shape: WidgetStateProperty.all(
                    RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                  padding: WidgetStateProperty.all<EdgeInsets>(
                    const EdgeInsets.only(
                      top: 13,
                      bottom: 13,
                      left: 28.5,
                      right: 28.5,
                    ),
                  ),
                ),
                onPressed: () {
                _adicionarAula();
                },
                child: const SizedBox(
                  width: double.infinity,
                  child: Text(
                    "Nova aula",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      fontSize: 15,
                      fontWeight: FontWeight.w900,
                      color: Color(0xff029846),
                    ),
                  ),
                ),
              ),
            ),
            const SizedBox(
              width: 16,
            ),
          ],
        ),
      ],
    );
  }
}

class AulaModel {
  final String idAula;
  final String titulo;
  final String descricao;
  final DateTime criadoem;
  final DateTime atualizadoem;

  // Construtor a partir de um Map
  AulaModel({
    required this.idAula,
    required this.titulo,
    required this.descricao,
    required this.criadoem,
    required this.atualizadoem,
  });

  AulaModel.fromMap(Map<String, dynamic> map)
      : assert(map["idAula"] != null),
        assert(map["titulo"] != null),
        assert(map["descricao"] != null),
        assert(map["criadoem"] != null),
        assert(map["atualizadoem"] != null),
        idAula = map["idAula"],
        titulo = map["titulo"],
        descricao = map["descricao"],
        criadoem = map["criadoem"],
        atualizadoem = map["atualizadoem"];
}

class ModuloModel {
  final String idModulo;
  final String titulo;
  final List<String> aulas;
  final List<String> materialDeApoio;
  final DateTime criadoem;
  final DateTime atualizadoem;

  // Construtor a partir de um Map
  ModuloModel({
    required this.idModulo,
    required this.titulo,
    required this.aulas,
    required this.materialDeApoio,
    required this.criadoem,
    required this.atualizadoem,
  });

  ModuloModel.fromMap(Map<String, dynamic> map)
      : assert(map["idModulo"] != null),
        assert(map["titulo"] != null),
        assert(map["aulas"] != null),
        assert(map["materialDeApoio"] != null),
        assert(map["criadoem"] != null),
        assert(map["atualizadoem"] != null),
        idModulo = map["idModulo"],
        titulo = map["titulo"],
        aulas = map["aulas"],
        materialDeApoio = map["materialDeApoio"],
        criadoem = map["criadoem"],
        atualizadoem = map["atualizadoem"];
}

2

Answers


  1. Chosen as BEST ANSWER

    I'm creating this comment to close the post here on StackOverflow.

    The temporary solution is to work with a list of type Map that will control both lists, even if the list is passed to a child Widget.

    The complete solution is:

    // Copyright 2019 the Dart project authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license
    // that can be found in the LICENSE file.
    
    import 'package:flutter/material.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            colorSchemeSeed: Colors.blue,
          ),
          home: const CriarCursoProfessorModulo(),
        );
      }
    }
    
    class CriarCursoProfessorModulo extends StatefulWidget {
      const CriarCursoProfessorModulo({super.key});
    
      @override
      State<CriarCursoProfessorModulo> createState() =>
          _CriarCursoProfessorModuloState();
    }
    
    class _CriarCursoProfessorModuloState extends State<CriarCursoProfessorModulo>
        with SingleTickerProviderStateMixin {
      late AnimationController _controller;
      late Animation<double> _animation;
      bool _isExpanded = true;
    
      Map<ModuloModel, List<AulaModel>> listaDeModulosAulas = {};
    
      void _toggleExpansion() {
        setState(() {
          _isExpanded = !_isExpanded;
          if (_isExpanded) {
            _controller.reverse();
          } else {
            _controller.forward();
          }
        });
      }
    
      @override
      void dispose() {
        _controller.dispose();
        super.dispose();
      }
    
      @override
      void initState() {
        super.initState();
        _controller = AnimationController(
          vsync: this,
          duration: const Duration(milliseconds: 300),
        );
        _animation = Tween<double>(begin: 1, end: 0).animate(_controller);
    
        // Exemplo de módulo inicial
        ModuloModel moduloModel = ModuloModel(
          idModulo: "1",
          titulo: "Módulo 1",
          aulas: [],
          materialDeApoio: [],
          criadoem: DateTime.now(),
          atualizadoem: DateTime.now(),
        );
    
        listaDeModulosAulas.addAll({
          moduloModel: [],
        });
      }
    
      @override
      Widget build(BuildContext context) {
        bool lightMode =
            MediaQuery.of(context).platformBrightness == Brightness.light;
    
        return Scaffold(
          backgroundColor: lightMode ? Colors.white : Colors.white,
          body: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
              
    
              
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 24.0),
                  child: Column(
                    children: [
                    TextButton.icon(
                            style: ButtonStyle(
                              backgroundColor: WidgetStateProperty.all<Color>(
                                const Color(0xff029846),
                              ),
                              shape: WidgetStateProperty.all(RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(4),
                              )),
                              padding: WidgetStateProperty.all<EdgeInsets>(
                                const EdgeInsets.only(
                                  top: 10,
                                  bottom: 10,
                                  left: 16,
                                  right: 16,
                                ),
                              ),
                            ),
                            onPressed: () {
                              ModuloModel moduloModel = ModuloModel(
                                idModulo: "",
                                titulo: "",
                                aulas: [],
                                materialDeApoio: [],
                                criadoem: DateTime.now(),
                                atualizadoem: DateTime.now(),
                              );
    
                              setState(() {
                                listaDeModulosAulas.addAll({
                                  moduloModel: [],
                                });
                              });
                            },
                            icon: const Icon(
                              Icons.add,
                              color: Colors.white,
                            ),
                            label: const SizedBox(
                              child: Text(
                                "Novo módulo",
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                  fontSize: 15,
                                  fontWeight: FontWeight.w900,
                                  color: Color(0xffFFFFFF),
                                ),
                              ),
                            ),
                          ),
                      ListView.builder(
                        shrinkWrap: true,
                        itemCount: listaDeModulosAulas.length,
                        physics: const NeverScrollableScrollPhysics(),
                        itemBuilder: (BuildContext context, int index) {
                          ModuloModel modulo =
                              listaDeModulosAulas.keys.elementAt(index);
                          List<AulaModel> aulas =
                              listaDeModulosAulas.values.elementAt(index);
                          return Card(
                            elevation: 0.0,
                            color: Colors.white,
                            borderOnForeground: true,
                            shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(16.0),
                              side: const BorderSide(
                                color: Color(0xffA9A9A9),
                                width: 1,
                              ),
                            ),
                            child: Padding(
                              padding: const EdgeInsets.only(
                                left: 16.0,
                                right: 16.0,
                                top: 8,
                                bottom: 8,
                              ),
                              child: Column(
                                mainAxisSize: MainAxisSize
                                    .min, // Permite que a Column encolha
                                children: [
                                  Row(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceBetween,
                                    children: [
                                      Text(
                                        modulo.titulo,
                                        style: const TextStyle(
                                          fontWeight: FontWeight.w500,
                                          fontSize: 16,
                                          color: Color(0xff404040),
                                        ),
                                      ),
                                      IconButton(
                                        onPressed: _toggleExpansion,
                                        icon: AnimatedSwitcher(
                                          duration:
                                              const Duration(milliseconds: 300),
                                          transitionBuilder: (Widget child,
                                              Animation<double> animation) {
                                            return FadeTransition(
                                              opacity: animation,
                                              child: ScaleTransition(
                                                scale: animation,
                                                child: child,
                                              ),
                                            );
                                          },
                                          child: _isExpanded
                                              ? const Icon(
                                                  Icons.keyboard_arrow_up_outlined)
                                              : const Icon(Icons
                                                  .keyboard_arrow_down_outlined),
                                        ),
                                      ),
                                    ],
                                  ),
                                  SizeTransition(
                                    // Anima o tamanho do botão
                                    sizeFactor: _animation,
                                    child: Column(
                                      children: [
                                        AulaWidget(
                                          aulas: aulas,
                                          aoMudarAula: (novasAulas) {
                                            setState(() {
                                              listaDeModulosAulas[modulo] =
                                                  novasAulas;
                                            });
                                          },
                                        ),
                                        TextButton(
                                          style: ButtonStyle(
                                            backgroundColor:
                                                WidgetStateProperty.all<Color>(
                                              const Color(0xffF44336)
                                                  .withOpacity(0.08),
                                            ),
                                            shape: WidgetStateProperty.all(
                                              RoundedRectangleBorder(
                                                borderRadius:
                                                    BorderRadius.circular(12),
                                              ),
                                            ),
                                            padding:
                                                WidgetStateProperty.all<EdgeInsets>(
                                              const EdgeInsets.only(
                                                top: 13,
                                                bottom: 13,
                                                left: 28.5,
                                                right: 28.5,
                                              ),
                                            ),
                                          ),
                                          onPressed: () {
                                            setState(() {
                                              listaDeModulosAulas.remove(modulo);
                                            });
                                          },
                                          child: const SizedBox(
                                            width: double.infinity,
                                            child: Text(
                                              "Excluir módulo",
                                              textAlign: TextAlign.center,
                                              style: TextStyle(
                                                fontSize: 14,
                                                fontWeight: FontWeight.w900,
                                                color: Color(0xffF44336),
                                              ),
                                            ),
                                          ),
                                        ),
                                        const SizedBox(
                                          height: 16,
                                        ),
                                      ],
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
                   
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class AulaWidget extends StatefulWidget {
      final List<AulaModel>? aulas;
      final ValueChanged<List<AulaModel>>? aoMudarAula;
      const AulaWidget({
        super.key,
        this.aulas,
        this.aoMudarAula,
      });
    
      @override
      State<AulaWidget> createState() => _AulaWidgetState();
    }
    
    class _AulaWidgetState extends State<AulaWidget> {
      final FocusScopeNode _focusScopeNode = FocusScopeNode();
    
      @override
      void dispose() {
        _focusScopeNode.dispose();
        super.dispose();
      }
    
      // Função para adicionar uma aula
      void _adicionarAula() {
        setState(() {
          widget.aulas!.add(AulaModel(
            idAula: "1",
            titulo: "Nova Aula",
            descricao: "",
            criadoem: DateTime.now(),
            atualizadoem: DateTime.now(),
          ));
          widget.aoMudarAula!(widget.aulas!);
        });
      }
    
      // Função para remover uma aula
      void _removerAula(int index) {
        setState(() {
          widget.aulas!.removeAt(index);
          widget.aoMudarAula!(widget.aulas!);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            ListView.builder(
              itemCount: widget.aulas!.length,
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemBuilder: (BuildContext context, int index) {
                AulaModel aulaModel = widget.aulas!.elementAt(index);
                return Container(
                  decoration: BoxDecoration(
                    color: const Color(0xffF6F6F6),
                    borderRadius: BorderRadius.circular(4),
                  ),
                  padding: const EdgeInsets.only(
                    top: 17,
                    bottom: 17,
                    right: 16,
                    left: 16,
                  ),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Expanded(
                        child: Row(
                          children: [
                            const Icon(
                              Icons.play_circle,
                              color: Color(0xff2196F3),
                            ),
                            const SizedBox(
                              width: 8,
                            ),
                            Flexible(
                              child: Text(
                                aulaModel.titulo,
                                style: const TextStyle(
                                  color: Color(0xff2196F3),
                                  fontSize: 14,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                      Row(
                        crossAxisAlignment: CrossAxisAlignment.end,
                        children: [
                          IconButton(
                            onPressed: () {},
                            icon: const Icon(
                              Icons.edit,
                              color: Color(0xff2A2E45),
                            ),
                          ),
                          IconButton(
                            onPressed: () {
                              _removerAula(index);
                            },
                            icon: const Icon(
                              Icons.delete,
                              color: Color(0xffF44336),
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                );
              },
            ),
            const SizedBox(
              height: 16,
            ),
            Row(
              children: [
                Expanded(
                  child: TextButton(
                    style: ButtonStyle(
                      backgroundColor: WidgetStateProperty.all<Color>(
                        const Color(0xff029846).withOpacity(0.08),
                      ),
                      shape: WidgetStateProperty.all(
                        RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(12),
                        ),
                      ),
                      padding: WidgetStateProperty.all<EdgeInsets>(
                        const EdgeInsets.only(
                          top: 13,
                          bottom: 13,
                          left: 28.5,
                          right: 28.5,
                        ),
                      ),
                    ),
                    onPressed: () {
                    _adicionarAula();
                    },
                    child: const SizedBox(
                      width: double.infinity,
                      child: Text(
                        "Nova aula",
                        textAlign: TextAlign.center,
                        style: TextStyle(
                          fontSize: 15,
                          fontWeight: FontWeight.w900,
                          color: Color(0xff029846),
                        ),
                      ),
                    ),
                  ),
                ),
                const SizedBox(
                  width: 16,
                ),
              ],
            ),
          ],
        );
      }
    }
    
    class AulaModel {
      final String idAula;
      final String titulo;
      final String descricao;
      final DateTime criadoem;
      final DateTime atualizadoem;
    
      // Construtor a partir de um Map
      AulaModel({
        required this.idAula,
        required this.titulo,
        required this.descricao,
        required this.criadoem,
        required this.atualizadoem,
      });
    
      AulaModel.fromMap(Map<String, dynamic> map)
          : assert(map["idAula"] != null),
            assert(map["titulo"] != null),
            assert(map["descricao"] != null),
            assert(map["criadoem"] != null),
            assert(map["atualizadoem"] != null),
            idAula = map["idAula"],
            titulo = map["titulo"],
            descricao = map["descricao"],
            criadoem = map["criadoem"],
            atualizadoem = map["atualizadoem"];
    }
    
    class ModuloModel {
      final String idModulo;
      final String titulo;
      final List<String> aulas;
      final List<String> materialDeApoio;
      final DateTime criadoem;
      final DateTime atualizadoem;
    
      // Construtor a partir de um Map
      ModuloModel({
        required this.idModulo,
        required this.titulo,
        required this.aulas,
        required this.materialDeApoio,
        required this.criadoem,
        required this.atualizadoem,
      });
    
      ModuloModel.fromMap(Map<String, dynamic> map)
          : assert(map["idModulo"] != null),
            assert(map["titulo"] != null),
            assert(map["aulas"] != null),
            assert(map["materialDeApoio"] != null),
            assert(map["criadoem"] != null),
            assert(map["atualizadoem"] != null),
            idModulo = map["idModulo"],
            titulo = map["titulo"],
            aulas = map["aulas"],
            materialDeApoio = map["materialDeApoio"],
            criadoem = map["criadoem"],
            atualizadoem = map["atualizadoem"];
    }
    
    

  2. In short, You don’t need to use nested ListView, for inner ListView replace with Column and render the children .

    class _AulaWidgetState extends State<AulaWidget> {
      List<String> listaDeAulas = List<String>.generate(5, (index) => 'Aula $index');
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            ...listaDeAulas.map((e) => ListTile(
                  leading: IconButton(
                    icon: const Icon(Icons.delete),
                    onPressed: () {
                      setState(() {
                        listaDeAulas.remove(e);
                      });
                    },
                  ),
                  title: Text("Sinais de Trânsito ${e}"),
                )),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: () {
                      setState(() {
                        listaDeAulas.add('Aula ${listaDeAulas.length}');
                      });
                    },
                    child: const Text('Adicionar Aula'),
                  ),
                ),
              ],
            ),
          ],
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search