fluttersinglechildscrollview

Flutter: Making Entire Screen Scrollable After Dynamically Adding Content


In my Flutter application, I'm facing a challenge with making my screen scrollable to deal with dynamically added content. Initially, I have a Form displayed on the screen with several TextFormField widgets. Users can add pictures from their phone, which are then displayed on the screen along with additional TextFormField widgets for labeling the images. Despite using SingleChildScrollView, I can't seem to achieve the desired scrollable effect for the entire screen after adding the pictures.

Below is the code snippet I'm working with:

return Scaffold(
  body: SafeArea(
    child: Column(
      children: [
        Expanded(
          child: SingleChildScrollView(
            child: Form(
              key: _formKey,
              child: Column(
                children: <Widget>[
                  // TextFormFields for input
                  Visibility(
                    visible: ref.watch(selectedImagesProvider).isNotEmpty,
                    child: ListView.builder(
                      itemCount: selectedImages.length,
                      itemBuilder: (context, index) {
                        // Display added images with TextFormField for each
                      },
                    ),
                  ),
                  // Button for adding/changing images
                ],
              ),
            ),
          ),
        ),
        // Upload button
      ],
    ),
  ),
);

My goal is for the entire page to be scrollable once images are added, not just the images section. Currently, if many pictures are added, they extend beyond the screen size, but I cannot scroll through all the content seamlessly.

I tried following Diego's suggestion but couldn't get the result I wanted. Is there an alternative approach to ListView.builder that would allow the images and the form to be part of a single, scrollable page? I want to avoid having the images section be independently scrollable from the rest of the form.

Any advice on how to adjust my layout or components to achieve a fully scrollable page that dynamically adjusts to content would be greatly appreciated.

Thank you for your help!


Solution

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

    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'),
                ),
              ],
            ),
          ),
        );
      }
    }