Flutter scrollable page with dynamic contents

72 Views Asked by At

How can I make sure the screen is scrollable when I add content through user interactions?

I have a situation in which a form is shown on the screen. Everything is static and fine. Then the user can add pictures from his phone which are then supposed to be shown with textfields under them to provide labels. However I use SingleChildScrollView I cannot make it work.

I have tried to implement Diego's suggestion but have failed to achieve the desired result.

return Scaffold(
  body: SafeArea(
    child: Column(
      children: [
        Expanded(
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                children: <Widget>[
                  TextFormField(),
                  TextFormField(),
                  TextFormField(),
                  TextFormField(),
                  Visibility(
                    visible: ref.watch(selectedImagesProvider).isNotEmpty,
                    child: ListView.builder(
                      itemCount: selectedImages.length,
                      itemBuilder: (context, index) {
                        return Column(
                          children: [
                            Image.file(
                              File(selectedImages[index].path),
                              width: 100, 
                              height: 100, 
                              fit: BoxFit.cover, 
                            ),
                            TextFormField(),
                            const SizedBox(height: 10),
                          ],
                        );
                      }
                    )
                  ),
                  const SizedBox(height: 20,),
                  ElevatedButton(
                    onPressed: () async {
                      final pickedFiles = await imagePicker.pickMultiImage();
                      if (pickedFiles.isNotEmpty) {
                        ref.read(selectedImagesProvider.notifier).state = pickedFiles.map((pickedFile) => File(pickedFile.path)).toList();
                      }
                    },
                    child: selectedImages.isNotEmpty ? 
                      const Text('Change images', style: TextStyle(color: Colors.black)) : 
                      const Text('Add images', style: TextStyle(color: Colors.black))
                  ),
                  const SizedBox(height: 10,),
                ]
              ),
            ),
          ),
        ),
        ElevatedButton(
          onPressed: () => null,
          child: const Text(
            "Upload",
            style: TextStyle(
              color: Colors.black
            ),
          ),
        )
      ]
    ),
  )
);

What do I have to change such that the entirety of the screen is scrollable? Can I replace the Listview.builder with something else? I don't want the added pictures to be scrollable themselves, but be a part of the scrollable page.

Thank you!

All the best

1

There are 1 best solutions below

6
diegoveloper On BEST ANSWER

You don't need to add extra complex Widget for this, all what you need are:

  • SingleChildScrollView (to make your list of items scrollable), this should be the parent of your Column.
  • Column (where you put your items in vertical layout).
  • Expanded (to force the list of items expand to all the screen available).

I added a button at the bottom and it's fixed, so you will always see the button and don't need to scroll.

Result:

enter image description here

Code:

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

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  // Replace `Widget` by `File` if you want.
  List<Widget> list = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              child: SingleChildScrollView(
                child: Form(
                  child: Column(
                    children: <Widget>[
                      ...List.generate(
                        5,
                        (index) => const Padding(
                          padding: EdgeInsets.all(15.0),
                          child: TextField(),
                        ),
                      ),
                      if (list.isNotEmpty) ...[
                        ...List.generate(
                          list.length,
                          (index) => Padding(
                            padding: const EdgeInsets.all(15.0),
                            child: list[index],
                          ),
                        ),
                      ],
                    ],
                  ),
                ),
              ),
            ),
            // BUTTON
            ElevatedButton(
              onPressed: () {
                // you can replace the placeholder to any File
                setState(() {
                  list.add(const Placeholder(
                    fallbackHeight: 100,
                    fallbackWidth: 100,
                  ));
                });
              },
              child: const Text('Add Item'),
            ),
          ],
        ),
      ),
    );
  }
}