Listview doesn’t update on the screen!

Asked

Viewed 264 times

0

I’d like to ask for a beginner’s help on Flutter/Dart. I’m programming an app to add cards that represent real estate, and each card represents a property within a Listview. But I can’t update Listview after adding a new item to the list of cards that is rendered in a Listview, where each item in the list is a card.

Main code (main.Dart):

import 'package:flutter/material.dart';
import 'models/imovel.dart';

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

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Vistoriador',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: HomePage(),
    );
  }
}

// ignore: must_be_immutable
class HomePage extends StatefulWidget {
  var imoveis = new List<Imovel>();

  HomePage() {
    imoveis = [];
    imoveis.add(Imovel(id: "1", endereco: "Rua Salvador Milego, 100"));
    imoveis.add(Imovel(id: "2", endereco: "Rua José Dolles, 53"));
    imoveis.add(Imovel(id: "3", endereco: "Rua Júlia Martins Domingues, 883"));
  }

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController myController = TextEditingController();

  Future<String> createAlertDialog(BuildContext context) {
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text("Endereço do Imóvel:"),
            content: TextField(controller: myController),
            actions: <Widget>[
              MaterialButton(
                elevation: 5.0,
                child: Text("Criar"),
                onPressed: () {
                  Navigator.of(context).pop(myController.text.toString());
                },
              )
            ],
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Imóveis"),
      ),
      body: ListView.builder(
          itemCount: widget.imoveis.length,
          itemBuilder: (BuildContext ctxt, int index) {
            final imovel = widget.imoveis[index];
            return Center(
              child: Dismissible(
                child: Card(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      ListTile(
                        leading: Icon(Icons.home),
                        title: Text("Vistoria " + imovel.id),
                        subtitle: Text(imovel.endereco),
                      ),
                      ButtonBar(
                        children: <Widget>[
                          IconButton(icon: Icon(Icons.edit), onPressed: null),
                        ],
                      ),
                    ],
                  ),
                ),
                key: Key(imovel.id),
              ),
            );
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          createAlertDialog(context).then((onValue) {
            widget.imoveis.add(
              Imovel(
                endereco: myController.text.toString(),
              ),
            );
            myController.text = "";
          });
        },

        /*criar instancia e adicionar vistoria*/
        child: Icon(Icons.add),
        backgroundColor: Colors.blue[800],
      ),
    );
  }
}

Immobile model code.Dart:

class Imovel {
  String id;
  String endereco;
  Comodos comodos;

  Imovel({this.id, this.endereco, this.comodos});

  Imovel.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    endereco = json['endereco'];
    comodos =
        json['comodos'] != null ? new Comodos.fromJson(json['comodos']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    data['endereco'] = this.endereco;
    if (this.comodos != null) {
      data['comodos'] = this.comodos.toJson();
    }
    return data;
  }
}

class Comodos {
  String descricao;
  String paredes;
  String paredeTras;
  String paredeEsquerda;
  String paredeDireita;
  String paredeFrente;
  String observacao;

  Comodos(
      {this.descricao,
      this.paredes,
      this.paredeTras,
      this.paredeEsquerda,
      this.paredeDireita,
      this.paredeFrente,
      this.observacao});

  Comodos.fromJson(Map<String, dynamic> json) {
    descricao = json['descricao'];
    paredes = json['paredes'];
    paredeTras = json['parede_tras'];
    paredeEsquerda = json['parede_esquerda'];
    paredeDireita = json['parede_direita'];
    paredeFrente = json['parede_frente'];
    observacao = json['observacao'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['descricao'] = this.descricao;
    data['paredes'] = this.paredes;
    data['parede_tras'] = this.paredeTras;
    data['parede_esquerda'] = this.paredeEsquerda;
    data['parede_direita'] = this.paredeDireita;
    data['parede_frente'] = this.paredeFrente;
    data['observacao'] = this.observacao;
    return data;
  }
}

Canvases: inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

2 answers

3


You have two problems in your implementation.

Improving

Move the list into the state class.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  List<Imovel> imoveis = <Imovel>[];

  @override
  initState() {
    super.initState();
    imoveis.add(Imovel(id: "1", endereco: "Rua Salvador Milego, 100"));
    imoveis.add(Imovel(id: "2", endereco: "Rua José Dolles, 53"));
    imoveis.add(Imovel(id: "3", endereco: "Rua Júlia Martins Domingues, 883"));
  }
 [...]

1st Problem: You need to call the SetState when inserting the new item, to tell Fltuter to redesign the widget.

setState((){
  imoveis.add(
    Imovel(
        endereco: myController.text.toString(),
    ),
  );
});

2nd problem: You need to inform the ID for your new item, this because you use the ID to mount the title, so it is NULL of an error.

setState((){
  imoveis.add(
    Imovel(
        id: (imoveis.length + 1).toString(),
        endereco: myController.text.toString(),
    ),
  );
});

Full class:

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Vistoriador',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: HomePage(),
    );
  }
}

// ignore: must_be_immutable
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  List<Imovel> imoveis = <Imovel>[];

  @override
  initState() {
    super.initState();
    imoveis.add(Imovel(id: "1", endereco: "Rua Salvador Milego, 100"));
    imoveis.add(Imovel(id: "2", endereco: "Rua José Dolles, 53"));
    imoveis.add(Imovel(id: "3", endereco: "Rua Júlia Martins Domingues, 883"));
  }
  
  TextEditingController myController = TextEditingController();

  Future<String> createAlertDialog(BuildContext context) {
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text("Endereço do Imóvel:"),
            content: TextField(controller: myController),
            actions: <Widget>[
              MaterialButton(
                elevation: 5.0,
                child: Text("Criar"),
                onPressed: () {
                  Navigator.of(context).pop(myController.text.toString());
                },
              )
            ],
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Imóveis"),
      ),
      body: ListView.builder(
          itemCount: imoveis.length,
          itemBuilder: (BuildContext ctxt, int index) {
            final imovel = imoveis[index];
            return Center(
              child: Dismissible(
                child: Card(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      ListTile(
                        leading: Icon(Icons.home),
                        title: Text("Vistoria " + imovel.id),
                        subtitle: Text(imovel.endereco),
                      ),
                      ButtonBar(
                        children: <Widget>[
                          IconButton(icon: Icon(Icons.edit), onPressed: null),
                        ],
                      ),
                    ],
                  ),
                ),
                key: Key(imovel.id),
              ),
            );
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          createAlertDialog(context).then((onValue) {
            setState((){
            imoveis.add(
              Imovel(id: (imoveis.length + 1).toString(),
                endereco: myController.text.toString(),
              ),
            );
            });
            myController.text = "";
          });
        },

        /*criar instancia e adicionar vistoria*/
        child: Icon(Icons.add),
        backgroundColor: Colors.blue[800],
      ),
    );
  }
}
  • Thanks @Matheus Ribeiro! It worked!

  • 1

    Opa fico feliz! Do not forget to mark the answer as accepted little face, to close your question.

0

Its variable imoveis = []; is a variable of state. That’s because your screen depends on it to build. So first move it into the state class _HomePageState :

class _HomePageState extends State<HomePage> {
  TextEditingController myController = TextEditingController();
imoveis = [Imovel(id: "1", endereco: "Rua Salvador Milego, 100"),
           Imovel(id: "2", endereco: "Rua José Dolles, 53"),
           Imovel(id: "3", endereco: "Rua Júlia Martins Domingues, 883"),
           ];
[...]

As in the example, you can declare the list already with the initial values inside it, however, if you prefer you can do inside the method initState, also within the state class.

The next step is to notify the framework when its state variable has been modified, using the method setState:

 floatingActionButton: FloatingActionButton(
        onPressed: () {
          createAlertDialog(context).then((onValue) {
            setState((){
                imoveis.add(
                  Imovel(
                    endereco: myController.text.toString(),
                  ),
            );
            });

            myController.text = "";
          });
        },

        /*criar instancia e adicionar vistoria*/
        child: Icon(Icons.add),
        backgroundColor: Colors.blue[800],
      ),

Your ListView is using the constructor Builder, which translating freely can be called builder. He builds his list based on context and content. What the setState is doing in this case is instructing this Builder to re-build your screen.

  • Naslausky, unfortunately it didn’t work. Dialog goes away, the data is accepted, but the new card with the address typed does not appear...

  • You have also corrected the itemCount property? itemCount: imoveis.length?

  • Yes I did!

  • However, if I change widget.immovable to immovable within Set State returns an invalid argument error.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.