Solucionado (ver solução)
Solucionado
(ver solução)
4
respostas

Problemas com o ListView

Eu estou criando uma aplicação, a ideia é ter um layout parecido com o do WhatsApp, onde eu tenho um TextField pra escrever uma mensagem e um FloattingActionButton que quando eu clicar ele vai pegar esta mensagem, vai criar uma box pra ela e exibir na tela. Pra colocar as mensagens de uma forma 'scrollable', tentei usar o ListView, mas quando eu o coloco, o TextField desaparece. Este é o código até o momento.

import 'dart:ui';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Morgan App',
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),
      home: Scaffold(
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.send),
          onPressed: () => {},
        ),
        backgroundColor: Colors.blue.shade900,
        body: TelaPrincipal(),
      ),
    );
  }
}

class TelaPrincipal extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(12.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Image.asset('images/img.png', height: 200),
          ListView(
            children: [
              UserMessage('Uma mensagem.'),
            ],
          ),
          Container(
            margin: EdgeInsets.fromLTRB(0, 0, 70, 0),
            child: TextField(
              style: TextStyle(fontSize: 20),
              decoration: InputDecoration(
                filled: true,
                fillColor: Colors.white,
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(Radius.circular(25)),
                ),
                hintText: 'Type here...',
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class UserMessage extends StatelessWidget {
  final String msg;
  UserMessage(this.msg);
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Card(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(msg, style: TextStyle(fontSize: 20)),
          ),
        ),
      ],
    );
  }
}

Uma coisa que eu queria saber também, é como eu faço pra posicionar a UserMessage logo acima do TextField, invés de aparecer no meio da tela entre ele e a imagem que eu coloquei.

4 respostas

Oi Murilo, tudo bem? Melhor do que eu ficar tentando explicar sou eu mostrar o código. Sou do time "show me the code" hahaha. E você mostrou o seu! Fiz algumas alterações que corrigiram o que você comentou. Também alinhei a imagem e mudei de stateless para statefull para a adição de tarefas na lista ser feita. Deixei minhas alterações comentadas no código. Olha e me fala o que achou. Caso esta resposta resolva o seu problema, marca ela como solução para ajudar a gente a organizar o fórum.

Abração!

solução!
import 'dart:ui';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Morgan App',
      theme: ThemeData(
        primaryColor: Colors.blue,
      ),

      // Tirei a responsabilidade do MyApp de exibir a tela e passei para o
      //  Widget TelaPrincipal, ok? Assim se você quiser quebrar ele em um outro
      //  arquivo este aqui pode servir de main.dart
      home: TelaPrincipal()
    );
  }
}

// Converti esse widget para stateful, assim, você consegue ter a ação de adicionar nele.
// Estando stateless ele seria completamente estático e você não conseguiria alterar nada na lista
class TelaPrincipal extends StatefulWidget {
  @override
  _TelaPrincipalState createState() => _TelaPrincipalState();
}

class _TelaPrincipalState extends State<TelaPrincipal> {
  // Criei a lista em uma variável para ela ser dinâmica e podermos adicionar itens
  // a ela através do floatingActionButton
  List<UserMessage> messages = List<UserMessage>();

  // Criei um controller para lermos os dados vindos do campo de texto digitado
  // e posteriormente utilizar este texto para add na lista de tarefas
  TextEditingController _taskController = TextEditingController();


  @override
  Widget build(BuildContext context) {

    return Scaffold(
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.send),
          onPressed: () {

            // Atualiza o estado da aplicação para a tela ser reconstruída e
            // exibir a nova tarefa na lista
            setState(() {
              // Adiciona a tarefa na lista
              messages.add(UserMessage(_taskController.text));

              // Limpa o campo de texto após adicionar a tarefa
              _taskController.text = "";
            });
          },
        ),
        backgroundColor: Colors.blue.shade900,
        body: Padding(
        padding: const EdgeInsets.all(12.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          crossAxisAlignment: CrossAxisAlignment.end, // Esta configuração alinha todos os elementos ao final da tela (lado direito), inclusive a img que você queria assim :)

          children: <Widget>[
            // Image.asset('images/img.png', height: 200),
            Image.network('https://pt.freelogodesign.org/Content/img/logo-samples/flooop.png', height: 200),

            // Precisamos inserir um expanded para dar a altura e largura máxima disponíveis
            // para a lista. Assim, ela ocupará todo o espaço que não for utilizado pela img e campo de texto
            // Mudei o listview para o builder. o list view convencional não trabalha bem com
            // intens inseridos dinamicamente. O builder podemos passar um contador de itens para ele e uma lista dinâmica
            Expanded(
              child: ListView.builder(
                itemCount: messages.length,
                itemBuilder: (context, index) {
                  print(index);
                  return messages[index];
                }
              ),
            ),
            Padding(
              padding: EdgeInsets.fromLTRB(0, 20, 70, 0),
              child: TextField(
                //Adicionei o controller no campo para recuperarmos o texto dele
                controller: _taskController,
                style: TextStyle(fontSize: 20),
                decoration: InputDecoration(
                  filled: true,
                  fillColor: Colors.white,
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(25)),
                  ),
                  hintText: 'Type here...',
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// Como é um widget estático e que vai ser utilizado repetidas vezes,
// recomendo criar uma pasta chamada "componentes" ou "widgets" e colocar o UserMessage lá
// assim ele fica reaproveitável e alivia a tela principal de ter todo o cógido do app
class UserMessage extends StatelessWidget {
  final String msg;
  UserMessage(this.msg);
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.end,
      children: [
        Card(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(msg, style: TextStyle(fontSize: 20)),
          ),
        ),
      ],
    );
  }
}

Não aguentei, já fui testar, IRADO, na verdade, eu ia mudar pra statefull depois que testasse de forma estática, mas tu já me poupou o trabalho, vlw. Agora posso me focar nas minhas outras ideias, que envolvem uma tela de login, que bom que você tem um curso sobre isso.

Caaaara, que maneiro que gostou! Coloquei uma imagem qualquer ali vinda da internet só pra testar o tamanho do componente de imagem na tela. Pode retirar e usar a sua que vem dos assets, ok? :)

Qualquer dúvida só chamar! E, te espero no curso de formulários.