Back Button Not Working when implemented a ListView Builder Widget Flutter

I have this code which displays a back button, text, and then a listview builder widget.

When I remove the listview builder widget, the back button works fine, but when I add it back the back button breaks. I don’t know why this is happening and need this issue to be fixed pretty quickly. Thanks!

Here’s the code for the screen (everything works perfectly so the other screens passing in data are not included):

import 'package:flutter/material.dart';
import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen2.dart';

class SingleSelectListViewWithLogo extends StatefulWidget {
  final List<String> items;
  const SingleSelectListViewWithLogo({Key? key, required this.items}) : super(key: key);
  @override
  _SingleSelectListViewWithLogoState createState() =>
      _SingleSelectListViewWithLogoState();
}

class _SingleSelectListViewWithLogoState extends State<SingleSelectListViewWithLogo> {
  int? selectedIndex;

  void returnScreen(context) {
    print('returning');
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        fullscreenDialog: true,
        builder: (context) => screen2(),
      ),
    );
  }

  bool nextValid = false;

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Material(
      child: Container (
        decoration: const BoxDecoration(color: Colors.grey),
        height: size.height,
        width: double.infinity,
        child: Stack(
          children: <Widget> [
            Positioned(
              top: size.height * .06,
              left: size.width * .03,
              child: InkWell(
                onTap: () {
                  returnScreen(context);
                },
                child: Image.asset(
                  alignment: Alignment.topLeft,
                  "assets/images/back2.png",
                  width: size.width * .07,
                ),
              ),
            ),
            Positioned(
              top: size.height * .09,
              left: size.width * .4,
              child: const Text(
                style: TextStyle(fontSize: 30, color: Color.fromARGB(255, 4, 3, 3)),
                'Goals'
              )
            ),
            Positioned(
              top: size.height * .15,
              left: size.width * .07,
              child: const Text(
                style: TextStyle(fontSize: 20, color: Color.fromARGB(255, 49, 48, 48)),
                'What body type do you want to get?'
              )
            ),
            Positioned(
              top: size.height * .26,
              left: size.width * .4,
              child: const Text(
                style: TextStyle(fontSize: 15, color: Color.fromARGB(255, 33, 31, 31)),
                'Select 1'
              )
            ),
            ListView.builder(
              itemCount: widget.items.length,
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () {
                    setState(() {
                      selectedIndex = index;
                      nextValid = true;
                    });
                  },
                  child: Container(
                    height: size.height * .15,
                    decoration: BoxDecoration(
                      color: selectedIndex == index ? Color.fromARGB(255, 40, 188, 72) : Color.fromARGB(255, 202, 195, 195),
                      border: Border.all(
                        color: selectedIndex == index ? Color.fromARGB(255, 16, 66, 37) : Colors.transparent,
                        width: 3,
                      ),
                      borderRadius: BorderRadius.circular(10),
                    ),
                    padding: const EdgeInsets.symmetric(horizontal: 10),
                    margin: EdgeInsets.fromLTRB(16, index == 0 ? MediaQuery.of(context).size.height * 0.265 : 0, 16, 8),
                    child: Row(
                      children: [
                        Flexible(
                          child: Text(widget.items[index]),
                        )
                      ],
                    ),
                  ),
                );
              },
            ),
            Positioned(
              top: size.height * .86,
              left: size.width * .1,
              child: SizedBox(
                width: size.width * .8,
                height: size.height * .08,
                child: ElevatedButton(
                  style: ButtonStyle(                  
                    backgroundColor: MaterialStateProperty.all<Color>(!nextValid ? Color.fromRGBO(69, 75, 85, 1) : Color.fromARGB(255, 0, 147, 246)),
                  ),
                  child: const Text('Continue',
                    style: TextStyle(fontSize: 20),
                  ),
                  onPressed: () async {
                  },
                ),
              ),
            ),
          ]
        )
      )
    );
  }
}

Thanks!

>Solution :

The problem here is that you’re using Stack widget everywhere, even when you’re rendering the ListView.builder. When this is the case, the ListView.builder covers the whole screen, especially when not given a bounded height/width. In that case since everything is in a Stack, based on how you write the widgets inside it, some of them stay on top while others will stay on the bottom, therefore not tappable. If I were to rewrite this implementation I would go with a Column and it would be like the following:

 @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Material(
        child: SafeArea(
      child: Container(
          decoration: const BoxDecoration(color: Colors.grey),
          height: size.height,
          width: double.infinity,
          child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                InkWell(
                  onTap: returnScreen,
                  child: const Icon(Icons.back_hand),
                ),
                const Text(
                    style: TextStyle(
                        fontSize: 30, color: Color.fromARGB(255, 4, 3, 3)),
                    'Goals'),
                const Text(
                    style: TextStyle(
                        fontSize: 20, color: Color.fromARGB(255, 49, 48, 48)),
                    'What body type do you want to get?'),
                const Text(
                    style: TextStyle(
                        fontSize: 15, color: Color.fromARGB(255, 33, 31, 31)),
                    'Select 1'),
                Expanded(
                  child: ListView.builder(
                    itemCount: widget.items.length,
                    itemBuilder: (context, index) {
                      return GestureDetector(
                        onTap: () {
                          setState(() {
                            selectedIndex = index;
                            nextValid = true;
                          });
                        },
                        child: Container(
                          height: size.height * .15,
                          decoration: BoxDecoration(
                            color: selectedIndex == index
                                ? const Color.fromARGB(255, 40, 188, 72)
                                : const Color.fromARGB(255, 202, 195, 195),
                            border: Border.all(
                              color: selectedIndex == index
                                  ? const Color.fromARGB(255, 16, 66, 37)
                                  : Colors.transparent,
                              width: 3,
                            ),
                            borderRadius: BorderRadius.circular(10),
                          ),
                          padding: const EdgeInsets.symmetric(horizontal: 10),
                          margin: EdgeInsets.fromLTRB(
                              16,
                              index == 0
                                  ? MediaQuery.of(context).size.height * 0.265
                                  : 0,
                              16,
                              8),
                          child: Row(
                            children: [
                              Flexible(
                                child: Text(widget.items[index]),
                              )
                            ],
                          ),
                        ),
                      );
                    },
                  ),
                ),
                Positioned(
                  top: size.height * .86,
                  left: size.width * .1,
                  child: SizedBox(
                    width: size.width * .8,
                    height: size.height * .08,
                    child: ElevatedButton(
                      style: ButtonStyle(
                        backgroundColor: MaterialStateProperty.all<Color>(
                            !nextValid
                                ? const Color.fromRGBO(69, 75, 85, 1)
                                : const Color.fromARGB(255, 0, 147, 246)),
                      ),
                      child: const Text(
                        'Continue',
                        style: TextStyle(fontSize: 20),
                      ),
                      onPressed: () async {},
                    ),
                  ),
                ),
              ])),
    ));
  }

But if you’re adamant in using a Stack instead of Column this is how you should go with it:

@override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Material(
      child: Container(
        decoration: const BoxDecoration(color: Colors.grey),
        height: size.height,
        width: double.infinity,
        child: Stack(
          children: <Widget>[
            Positioned(
                top: size.height * .09,
                left: size.width * .4,
                child: const Text(
                    style: TextStyle(
                        fontSize: 30, color: Color.fromARGB(255, 4, 3, 3)),
                    'Goals')),
            Positioned(
                top: size.height * .15,
                left: size.width * .07,
                child: const Text(
                    style: TextStyle(
                        fontSize: 20, color: Color.fromARGB(255, 49, 48, 48)),
                    'What body type do you want to get?')),
            Positioned(
                top: size.height * .26,
                left: size.width * .4,
                child: const Text(
                    style: TextStyle(
                        fontSize: 15, color: Color.fromARGB(255, 33, 31, 31)),
                    'Select 1')),
            ListView.builder(
              itemCount: widget.items.length,
              itemBuilder: (context, index) {
                return GestureDetector(
                  onTap: () {
                    setState(() {
                      selectedIndex = index;
                      nextValid = true;
                    });
                  },
                  child: Container(
                    height: size.height * .15,
                    decoration: BoxDecoration(
                      color: selectedIndex == index
                          ? const Color.fromARGB(255, 40, 188, 72)
                          : const Color.fromARGB(255, 202, 195, 195),
                      border: Border.all(
                        color: selectedIndex == index
                            ? const Color.fromARGB(255, 16, 66, 37)
                            : Colors.transparent,
                        width: 3,
                      ),
                      borderRadius: BorderRadius.circular(10),
                    ),
                    padding: const EdgeInsets.symmetric(horizontal: 10),
                    margin: EdgeInsets.fromLTRB(
                        16,
                        index == 0
                            ? MediaQuery.of(context).size.height * 0.265
                            : 0,
                        16,
                        8),
                    child: Row(
                      children: [
                        Flexible(
                          child: Text(widget.items[index]),
                        )
                      ],
                    ),
                  ),
                );
              },
            ),
            Positioned(
              top: size.height * .86,
              left: size.width * .1,
              child: SizedBox(
                width: size.width * .8,
                height: size.height * .08,
                child: ElevatedButton(
                  style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all<Color>(!nextValid
                        ? const Color.fromRGBO(69, 75, 85, 1)
                        : const Color.fromARGB(255, 0, 147, 246)),
                  ),
                  child: const Text(
                    'Continue',
                    style: TextStyle(fontSize: 20),
                  ),
                  onPressed: () async {},
                ),
              ),
            ),
            Positioned(
              top: size.height * .06,
              left: size.width * .03,
              child: InkWell(
                onTap: () {
                  returnScreen(context);
                },
                child: Image.asset(
                  alignment: Alignment.topLeft,
                  "assets/images/back2.png",
                  width: size.width * .07,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

Notice how I put the InkWell as the last child of the Stack, so it stays at the top and becomes tappable.

Leave a Reply