skip to Main Content

I have been searching for so long to find a good solution to my problem. I want to have this layout:

enter image description here enter image description here

So far I have managed to do this:

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

  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  bool hasManyData = false;

  // List of many data
  final List<String> dataLong = List.generate(20, (index) => "Data $index");

  // List of few data
  final List<String> dataShort = List.generate(2, (index) => "Data $index");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                setState(() {
                  hasManyData = !hasManyData;
                });
              },
              child: const Text("change Data Size"),
            ),
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  children: [
                    for (final data in hasManyData ? dataLong : dataShort)
                      ListTile(
                        title: Text(data),
                      ),
                    const TextField(
                      decoration: InputDecoration(
                        hintText: "Name",
                      ),
                    ),
                    ElevatedButton(
                      onPressed: () {},
                      child: const Text("Submit"),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

enter image description here

Which is almost the same but the submit button is not on the bottom when there are few data (you can change data size using the button).

Every way that I have tried so many things with Slivers and without always there was something breaking, I want to keep the keyboard functionality as is without overflowing or the Submit button moving up with the keyboard.

EDIT:
I have managed to do that:


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

  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  bool hasManyData = false;

  // List of many data
  final List<String> dataLong = List.generate(20, (index) => "Data $index");

  // List of few data
  final List<String> dataShort = List.generate(2, (index) => "Data $index");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                setState(() {
                  hasManyData = !hasManyData;
                });
              },
              child: const Text("change Data Size"),
            ),
            Expanded(
              child: CustomScrollView(
                slivers: [
                  SliverFillRemaining(
                    hasScrollBody: false,
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        for (final data in hasManyData ? dataLong : dataShort)
                          ListTile(
                            title: Text(data),
                          ),
                        const TextField(
                          decoration: InputDecoration(
                            hintText: "Name",
                          ),
                        ),
                        const Spacer(),
                        ElevatedButton(
                          onPressed: () {},
                          child: const Text("Submit"),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

But now the submit button gets pushed up when the keyboard opens, and hiding the button when the keyboard opens is an option… but a very bad one imo because it takes a second for it to reapear.

3

Answers


  1. You need to provide padding based on Keyboard’s height. and the the ElevatedButton will be outside the Expanded.

    Column(
      children: [
        TopButton(),
        Expanded(
          child: ListView(...)
         ),
        SubmitButton(),
        
        // you can wrap with the padding as well 
        SizedBox(height: MediaQuery.viewInsetsOf(context).bottom), 
        ],
      )
    
    Login or Signup to reply.
  2. First thing take out ElevatedButton from Expanded widget:

    Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {},
              child: const Text("change Data Size"),
            ),
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [],
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
                child: ElevatedButton(
                  onPressed: () {},
                  child: const Text("Submit"),
              ),
            ),
          ],
        ),
      ),
    )
    

    Align Button

    Another way to do this, use Align widget:

    Align(
      alignment: Alignment.bottomCenter,
      child: ElevatedButton(
        onPressed: () {},
        child: const Text("Submit"),
      ),
    )
    
    Login or Signup to reply.
  3. Try below code

    late final GlobalKey _key = GlobalKey();
    Column(
          children: [
            ElevatedButton(
              onPressed: () {
                setState(() {
                  hasManyData = !hasManyData;
                });
              },
              child: const Text("change Data Size"),
            ),
            Expanded(
              child: SingleChildScrollView(
                child: Column(
                  key: _key,
                  children: [
                    for (final data in hasManyData ? dataLong : dataShort)
                      ListTile(
                        title: Text(data),
                      ),
                    const TextField(
                      decoration: InputDecoration(
                        hintText: "Name",
                      ),
                    ),
                    Column(
                      children: [
                        SizedBox(height: height > MediaQuery.of(context).size.height ? MediaQuery.of(context).size.height/1.6 : 0),
                        ElevatedButton(
                          onPressed: () {},
                          child: const Text("Submit"),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search