CupertinoActionSheet throws infinite size during layout error

Issue

I get the following error when calling the CupertinoActionSheet when implementing SingleChildScrollView on my stateful widget:

_RenderCupertinoAlertActions object was given an infinite size during layout. The relevant error-causing widget was
CupertinoActionSheet lib\main.dart:82 The following RenderObject was being processed when the exception was fired:
_RenderCupertinoAlertActions#56898 relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE RenderObject:
_RenderCupertinoAlertActions#56898 relayoutBoundary=up19 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
constraints: BoxConstraints(w=395.4, 0.0<=h<=Infinity)
size: Size(395.4, Infinity)
child 1: RenderPointerListener#7df6e relayoutBoundary=up20 NEEDS-PAINT
parentData: offset=Offset(0.0, 0.0); id=null (can use size)
constraints: BoxConstraints(w=395.4, 0.0<=h<=Infinity)
size: Size(395.4, Infinity)
behavior: opaque
listeners: down

The full code is attached here (edited based on the comment below to resolve the infinite size error):

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  List<String> leaveTypes = ["Vacation Leave","Ordinary Sick Leave","Childcare Leave"];
  String applyLeaveType;

  @override
  Widget build(BuildContext context) {
    if(applyLeaveType == null){
      applyLeaveType = leaveTypes[0];
    };
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: LayoutBuilder(builder:(context, constraints){
        return SingleChildScrollView(
          /*child: ConstrainedBox(
            constraints: BoxConstraints(
              minWidth: constraints.maxWidth, minHeight: constraints.maxHeight
            ),*/
            child: Container(
              height: constraints.maxHeight,
              color: Color.fromARGB(255, 244, 246, 249),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  //Text for leave type
                  Container(                            
                    alignment: Alignment(-1.0,0.0),
                    padding:EdgeInsets.only(
                      top: 10, bottom: 5, left: 20, right: 20
                    ),
                    child: Text("I want to apply for",
                      style: TextStyle(fontSize: 16),
                      textAlign: TextAlign.left,
                    )
                  ),
                  SizedBox(
                    width: MediaQuery.of(context).size.width,
                    height:80,
                    child: GestureDetector(
                      onTap:() {
                        buildLeaveList(){
                          List<Widget> widgets = List();
                          leaveTypes.forEach((leaveType){
                            print(leaveType);
                            widgets.add(
                              CupertinoActionSheetAction(
                                child: Text(leaveType),
                                onPressed: () {
                                  setState(() {
                                    applyLeaveType = leaveType;
                                  });
                                  Navigator.pop(context);
                                }
                              )
                            );

                          });
                          return widgets;
                        }
                        final action = Container(
                          height: MediaQuery.of(context).size.height,
                          child: CupertinoActionSheet(

                            title: Text(
                              "Leave Type",
                              style: TextStyle(fontSize:16)
                            ),
                            actions: buildLeaveList(),
                            cancelButton: CupertinoActionSheetAction(
                              child: Text("Back"),
                              onPressed:(){
                                Navigator.pop(context);
                              }
                            )
                          )
                        );
                        showCupertinoModalPopup(context: context, builder: (context) => action);
                      },
                      child: Container(
                        alignment: Alignment(0.0,0.0),
                        padding:EdgeInsets.only(
                          top: 10, bottom: 10, left: 20, right: 20
                        ),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          //border: Border.all(),
                          //borderRadius: BorderRadius.all(Radius.circular(10))
                        ),                     
                        child:Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: <Widget>[
                            Container(
                              padding: EdgeInsets.all(10),
                              child: Text(applyLeaveType),
                            ),
                            Container(
                              padding: EdgeInsets.all(10),
                              child: Icon(Icons.keyboard_arrow_down)
                            )
                          ],
                        )
                      )
                    ),
                  )
                ]
              )
            )
          //)
        );  
      })  
    );
  }
}

Solution

Issues is that if you use any list then it requires specific height of their parent widget in which listview can build.

If you use ListView with ShrinkWrap: true and some other widget it will build but height of bottomsheet become height of whole screen.

Final solution:
We can create a variable in separate method and add all items into it and finally call that method in action.

Following code help you more to understand.

create following method:

 callme() {
    List<Widget> mywidget = List();
    leaveTypes.forEach((e) => mywidget.add(CupertinoActionSheetAction(
        child: Text(e),
        onPressed: () {
          setState(() {
            applyLeaveType = e;
          });
          Navigator.pop(context);
        })));
    return mywidget;
  }

Call this method in action in following way.

actions: callme()

Update:

Working Demo:

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<String> leaveTypes = [
    "Vacation Leave",
    "Ordinary Sick Leave",
    "Childcare Leave"
  ];
  String applyLeaveType;
  callme() {
    List<Widget> mywidget = List();
    leaveTypes.forEach((e) => mywidget.add(CupertinoActionSheetAction(
        child: Text(e),
        onPressed: () {
          setState(() {
            applyLeaveType = e;
          });
          Navigator.pop(context);
        })));
    return mywidget;
  }

  @override
  Widget build(BuildContext context) {
    if (applyLeaveType == null) {
      applyLeaveType = leaveTypes[0];
    }

    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: LayoutBuilder(builder: (context, constraints) {
          return SingleChildScrollView(
              child: Container(
                  height: constraints.maxHeight,
                  color: Color.fromARGB(255, 244, 246, 249),
                  child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        Container(
                            alignment: Alignment(-1.0, 0.0),
                            padding: EdgeInsets.only(
                                top: 10, bottom: 5, left: 20, right: 20),
                            child: Text(
                              "I want to apply for",
                              style: TextStyle(fontSize: 16),
                              textAlign: TextAlign.left,
                            )),
                        SizedBox(
                          width: MediaQuery.of(context).size.width,
                          height: 80,
                          child: GestureDetector(
                              onTap: () {
                                final action = Container(
                                    child: CupertinoActionSheet(
                                        title: Text("Leave Type",
                                            style: TextStyle(fontSize: 16)),
                                        actions: callme(),
                                        cancelButton:
                                            CupertinoActionSheetAction(
                                                child: Text("Back"),
                                                onPressed: () {
                                                  Navigator.pop(context);
                                                })));
                                showCupertinoModalPopup(
                                    context: context,
                                    builder: (context) => action);
                              },
                              child: Container(
                                  alignment: Alignment(0.0, 0.0),
                                  padding: EdgeInsets.only(
                                      top: 10, bottom: 10, left: 20, right: 20),
                                  decoration: BoxDecoration(
                                    color: Colors.white,
                                  ),
                                  child: Row(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceBetween,
                                    children: <Widget>[
                                      Container(
                                        padding: EdgeInsets.all(10),
                                        child: Text(applyLeaveType),
                                      ),
                                      Container(
                                          padding: EdgeInsets.all(10),
                                          child:
                                              Icon(Icons.keyboard_arrow_down))
                                    ],
                                  ))),
                        )
                      ])));
        }));
  }
}

Answered By – Viren V Varasadiya

Answer Checked By – Mildred Charles (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.