Search code examples
flutterlistviewflutter-listview

Trying to build a ListView with a horizontal scrollDirection - failing


I keep trying to display a simple ListView, which I will fill with data that I get as a response from my backend. First of all I wanted to display that simple ListView inside my MainPage widget but i keep receiving the following error. I couldn't find anything related to that error besides this solution, which mentions about wrapping up the ListView.builder in Expanded widget and adding shrinkWrap: true property. However, I keep getting the following error:

════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════ Updated layout information required for RenderFlex#c30cf relayoutBoundary=up11 NEEDS-LAYOUT NEEDS-PAINT to calculate semantics. 'package:flutter/src/rendering/object.dart': Failed assertion: line 3620 pos 12: '!_needsLayout' ════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by gestures library ══════════════════════════════════ Cannot hit test a render box that has never been laid out. ════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by gestures library ══════════════════════════════════ Cannot hit test a render box that has never been laid out. ════════════════════════════════════════════════════════════════════════════════

Here is the code of my ListView.builder, further down I will put the whole code of the MainPage widget: ListView

Expanded(
  child: ListView.builder(
    shrinkWrap: true,
    scrollDirection: Axis.horizontal,
    itemCount: 15,
    itemBuilder: (BuildContext context, int index) => Card(
      child: Center(child: Text('Dummy Card Text')),
    ),
  ),
),

whole widget

class MainPage extends ConsumerWidget {
  const MainPage({super.key});

  @override
  Widget build(BuildContext context, ref) {
    // provider
    // final _data = ref.watch(roomDataProvider);

    final roomIDController = TextEditingController();
    // UI screen size
    Size size = MediaQuery.of(context).size;

    double deviceWidth = size.width;
    double deviceHeight = size.height;

    return Scaffold(
      backgroundColor: bluePrimary,
      body: SafeArea(
          child: SingleChildScrollView(
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 36, vertical: 16),
          child: Column(
              //crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    IconButton(
                      iconSize: deviceWidth * 0.09,
                      icon: const Icon(Icons.person_outline,
                          color: orangePrimary),
                      onPressed: () {},
                    ),
                    IconButton(
                      icon: const Icon(
                        Icons.add,
                        color: orangePrimary,
                      ),
                      iconSize: deviceWidth * 0.09,
                      onPressed: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => const CreateRoomScreen()),
                        );
                      },
                    )
                  ],
                ),
                SizedBox(height: deviceHeight * 0.04),
                Align(
                  alignment: Alignment.centerLeft,
                  child: Text("W",
                      style: TextStyle(
                          fontFamily: 'Chalet',
                          fontSize: deviceWidth * 0.12,
                          color: orangePrimary,
                          fontWeight: FontWeight.w300,
                          height: deviceHeight * 0.001)),
                ),
                Align(
                  alignment: Alignment.centerLeft,
                  child: Text("W",
                      style: TextStyle(
                          fontFamily: 'Chalet',
                          fontSize: deviceWidth * 0.12,
                          color: whitePrimary,
                          fontWeight: FontWeight.w300,
                          height: deviceHeight * 0.001)),
                ),
                Align(
                  alignment: Alignment.centerLeft,
                  child: Text("M",
                      style: TextStyle(
                          fontFamily: 'Chalet',
                          fontSize: deviceWidth * 0.12,
                          color: orangePrimary,
                          fontWeight: FontWeight.w300,
                          height: deviceHeight * 0.001)),
                ),
                SizedBox(height: deviceHeight * 0.04),
                Align(
                  alignment: Alignment.centerLeft,
                  child: Text("Join room",
                      style: TextStyle(
                          fontFamily: 'Chalet',
                          fontSize: deviceWidth * 0.07,
                          color: whitePrimary,
                          fontWeight: FontWeight.w100,
                          height: deviceHeight * 0.001)),
                ),
                SizedBox(height: deviceHeight * 0.008),

                // email textField
                SizedBox(
                  width: MediaQuery.of(context).size.width * 0.85,
                  child: TextField(
                    controller: roomIDController,
                    decoration: InputDecoration(
                        filled: true,
                        fillColor: whitePrimary,
                        border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(12),
                            borderSide: BorderSide.none),
                        hintText: 'Enter room ID to join it',
                        hintStyle: const TextStyle(
                            color: Color.fromARGB(255, 174, 173, 173))),
                  ),
                ),

                SizedBox(height: deviceHeight * 0.016),

                Align(
                  alignment: Alignment.bottomRight,
                  child: FloatingActionButton(
                    backgroundColor: orangePrimary,
                    child: const Icon(Icons.arrow_forward_ios_rounded,
                        color: whitePrimary),
                    onPressed: () {},
                  ),
                ),

                SizedBox(height: deviceHeight * 0.020),

                Align(
                  alignment: Alignment.centerLeft,
                  child: Text("My rooms",
                      style: TextStyle(
                          fontFamily: 'Chalet',
                          fontSize: deviceWidth * 0.07,
                          color: whitePrimary,
                          fontWeight: FontWeight.w100,
                          height: deviceHeight * 0.001)),
                ),

                SizedBox(height: deviceHeight * 0.014),

                Expanded(
                  child: ListView.builder(
                    shrinkWrap: true,
                    scrollDirection: Axis.horizontal,
                    itemCount: 15,
                    itemBuilder: (BuildContext context, int index) => Card(
                      child: Center(child: Text('Dummy Card Text')),
                    ),
                  ),
                ),
              ]),
        ),
      )),
    );
  }
}

Solution

  • The problem is that you wrapped the ListView with an Expanded that is inside a Column, but the Column does not have constrained height since it's inside a SingleChildScrollView. The Expanded widget will try to fill the remaining height, but since it's inside a scrollable that run horizontally, there's no limit to the height. If you want to keep the scrolling behavior, you should give the ListView a fixed height instead of using Expanded:

    SizedBox(
      height: 100,
      child: ListView.builder(
        // ...
      ),
    ),
    

    Or if you want to make the ListView to actually fill the remaining height in the screen, remove the SingleChildScrollView widget.


    See also: