I am a beginner in Flutter. I am trying to add a new list item widget to screen when floating action button is pressed. How do I achieve this? I am trying to create a list of items. When the floating action button is clicked, a dialog box is prompted and user is asked to enter details. I want to add a new list item with these user input details. This is my input_page.dart file which I am calling in main.dart

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

class MedPage extends StatefulWidget {
  @override
  _MedPageState createState()=> _MedPageState();
}

class _MedPageState extends State<MedPage> {

  Future<String>createAlertDialog(BuildContext context) async{

    TextEditingController customController= new TextEditingController();
    return await showDialog(context: context,builder: (context) {
      return AlertDialog(
        title: Text("Name of the Pill"),
        content: TextField(
          controller: customController,
        ),
        actions: <Widget>[
          MaterialButton(
              elevation: 5.0,
              child: Text("OK"),
              onPressed: (){
                Navigator.of(context).pop(customController.text.toString()); // to go back to screen after submitting
              }
              )

        ],
      );
    });
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('My med app'),
      ),
      body: Center(

        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget> [
            Expanded(
              child: ListView(
                padding: const EdgeInsets.all(8),
                children: <Widget>[
                  ReusableListItem(Color(0xFFd2fddf),"Name 1"),

                  ReusableListItem(Colors.orange,"Name 2"),

                  ReusableListItem(Color(0xFF57a1ab), "Name 3"),
                ],

              ),
            ),

          ],
        ),

      ),

      floatingActionButton: FloatingActionButton(
        onPressed: (){
          print("Clicked");
          createAlertDialog(context).then((onValue){
            print(onValue);
            setState(() {

            });

          });

        },
        child: Icon(Icons.add),
      ),
    );

  }
}

class ReusableListItem extends StatelessWidget {
  ReusableListItem(this.colour,this.pill);

  Color colour;
  String pill;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50,
      margin: const EdgeInsets.all(8),
      decoration: BoxDecoration(
          color: colour,
          borderRadius: BorderRadius.circular(15.0)

      ),
        child: Center(
            child: Text(pill)
        ),

    );
  }
}


Solution 1: Hakkı Akut

Firstly you need to use ListView.builder() rather than ListView because you have dynamic content. Also you need to hold your items in a list.

// create a list before
ListView.builder(
    itemCount: list.length,
    itemBuilder: (BuildContext context, int index) {
     return Text(list[index]);
    }
  )

When you click on FloatingActionButton() you will call AlertDialog() method.

FloatingActionButton(
        onPressed: (){
AlertDialog(
    content:  Form(), // create your form here
    actions: [
// add a button here
]
   )
})

This method will show a dialog(you will add a form inside of the dialog). When the user completes the form(after clicking the button) you will add a new object to the list and update the state with setState({})

onPressed: (){
setState({
// add new object to the list here
});
Navigator.pop(context); // this will close the dialog
}


Solution 2: Ryan

You don't need to change much in your code, maintain a variable that stores the values entered to be able to show them in the list. You should use Listview.builder() in order to dynamically render the items.

Here's your code:

class MedPage extends StatefulWidget {
  @override
  _MedPageState createState() => _MedPageState();
}

class _MedPageState extends State<MedPage> {
  List<String> items = [];

  Future<String> createAlertDialog(BuildContext context) async {
    TextEditingController customController = new TextEditingController();
    return await showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text("Name of the Pill"),
            content: TextField(
              controller: customController,
            ),
            actions: <Widget>[
              MaterialButton(
                  elevation: 5.0,
                  child: Text("OK"),
                  onPressed: () {
                    Navigator.of(context).pop(customController.text
                        .toString()); // to go back to screen after submitting
                  })
            ],
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My med app'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Expanded(
              child: ListView.builder(
                itemBuilder: (context, index) {
                  return ReusableListItem(Color(0xFFd2fddf), items[index]);
                },
                itemCount: items.length,
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          print("Clicked");
          createAlertDialog(context).then((onValue) {
            // print(onValue);
            setState(() {
              items.add(onValue);
            });
          });
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

class ReusableListItem extends StatelessWidget {
  ReusableListItem(this.colour, this.pill);

  final Color colour;
  final String pill;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50,
      margin: const EdgeInsets.all(8),
      decoration:
          BoxDecoration(color: colour, borderRadius: BorderRadius.circular(15.0)),
      child: Center(child: Text(pill)),
    );
  }
}