Home > Software engineering >  Flutter can't render an Expanded Widget inside a SingleChildScrollView
Flutter can't render an Expanded Widget inside a SingleChildScrollView

Time:01-11

So i have this build method:

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: _createBody(),
  );
}


Widget _createBody(){
  return SafeArea(
    child: Column(
     children: [
      Container(
        margin: const EdgeInsets.only(top: 5, left: 10, right: 10),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text(
              "xOrder HD",
              style: TextStyle(
                color: Colors.blue[900],
                fontSize: 36
              ),
            ),
            Container(
              padding: const EdgeInsets.only(left: 13, top: 13),
              alignment: Alignment.bottomLeft,
              child: Text(AppVersion.xOrderVersion()),
            )
          ],
        )
      ),
      Container(
        margin: const EdgeInsets.symmetric(horizontal: 10),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text(
              AppLocalizations.of(context)!.solutionFor,
              textAlign: TextAlign.start,
            ),
          ],
        )
      ),
      Expanded(
        child: Container(
          margin: const EdgeInsets.only(left: 25, right: 25, top: 20, bottom: 10),
          child: Row(
            children: [
                Expanded(
                  child: Container(
                    child: Column(
                      children: [
                        Container(
                          padding: const EdgeInsets.symmetric(vertical: 10),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Text(
                                AppLocalizations.of(context)!.companyList,
                                style: const TextStyle(
                                  color: Colors.white,
                                  fontSize: 16,
                                  fontWeight: FontWeight.bold,
                                )
                              ),
                            ],
                          ),
                          decoration: BoxDecoration(
                            color: mainColor,
                            borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4))
                          ),
                        ),

                        _loadedAziende.isEmpty ? 
                          Expanded(
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Text(
                                  AppLocalizations.of(context)!.noCompanyFound,
                                  style: const TextStyle(
                                    color: Colors.black54,
                                    fontSize: 16
                                  )
                                ),
                                const SizedBox(height: 50,),
                                GestureDetector(
                                  onTap: () {
                                    Navigator.push(context, MaterialPageRoute(builder: (context) => QrCodeScanner(delegate: this,)));
                                  },
                                  child: Material(
                                    elevation: 5,
                                    borderRadius: const BorderRadius.all(Radius.circular(5)),
                                    child: Container(
                                      padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                                      child:  Row(
                                        mainAxisSize: MainAxisSize.min,
                                        children: [
                                          const Icon(Icons.add, color: Colors.white,),
                                          const SizedBox(width: 10,),
                                          Text(
                                            AppLocalizations.of(context)!.newCompany,
                                            style: const TextStyle(
                                              fontSize: 16,
                                              fontWeight: FontWeight.bold,
                                              color: Colors.white,
                                            )
                                          ),
                                        ],
                                      ),
                                      decoration: BoxDecoration(
                                        color: mainColor,
                                        borderRadius: const BorderRadius.all(Radius.circular(5))
                                      ),
                                    ),
                                  )
                                )
                              ],
                            )
                          )
                        :
                          Expanded(
                            child: Stack(
                              children: [
                                ListView.separated(
                                  itemCount: _aziendeToShow.length,
                                  itemBuilder: (ctx, index) {
                                    return InfoCell(
                                      info: _aziendeToShow[index],
                                      delegate: this,
                                    );
                                  }, 
                                  separatorBuilder: (ctx, index) => const Divider(height: 1,), 
                                ),
                                Positioned(
                                  bottom: 15,
                                  right: 15,
                                  child: GestureDetector(
                                    onTap: () {
                                      Navigator.push(context, MaterialPageRoute(builder: (context) => QrCodeScanner(delegate: this,)));
                                    },
                                    child: Container(
                                      padding: const EdgeInsets.all(10),
                                      child: const Icon(Icons.qr_code_scanner, color: Colors.white, size: 28),
                                      decoration: BoxDecoration(
                                        color: mainColor,
                                        shape: BoxShape.circle
                                      ),
                                    )
                                  )
                                )
                              ],
                            )
                          )
                      ],
                    ),
                    decoration: BoxDecoration(
                      color: Colors.grey[100],
                      border: Border.all(color: Colors.grey[500]!),
                      borderRadius: const BorderRadius.all(Radius.circular(5))
                    ),
                  ),
                ),
                if(_loadedAziende.isNotEmpty)
                  const SizedBox(width: 25,),
                if(_loadedAziende.isNotEmpty)
                  Expanded(
                    child: Container(
                      child: Column(
                        children: [
                          Container(
                            padding: const EdgeInsets.symmetric(vertical: 10),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Text(
                                  AppLocalizations.of(context)!.login,
                                  style: const TextStyle(
                                    color: Colors.white,
                                    fontSize: 16,
                                    fontWeight: FontWeight.bold,
                                  )
                                ),
                              ],
                            ),
                            decoration: BoxDecoration(
                              color: mainColor,
                              borderRadius: const BorderRadius.only(topLeft: Radius.circular(4), topRight: Radius.circular(4))
                            ),
                          ),

                          isEmptyOrNull(_selectedAzienda) ? 
                            Expanded(
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Text(
                                    AppLocalizations.of(context)!.selectAcompany,
                                    style: const TextStyle(
                                      color: Colors.black54,
                                      fontSize: 16
                                    )
                                  ),
                                ],
                              )
                            )
                          :
                            Expanded(
                              child: Column(
                                children: [
                                  Container(
                                    height: 150,
                                    margin: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
                                    decoration: BoxDecoration(
                                      shape: BoxShape.circle,
                                      border: Border.all(color: Colors.grey[400]!),
                                      image: DecorationImage(
                                        image: Image.network(_selectedAzienda!.aziendaLogo).image,
                                        fit: BoxFit.contain
                                      )
                                    ),
                                  ),
                                  Text(
                                    _selectedAzienda!.aziendaCode,
                                    style: const TextStyle(
                                      color: Colors.black,
                                      fontSize: 25,
                                      fontWeight: FontWeight.bold
                                    ),
                                  ),
                                  Container(
                                    margin: const EdgeInsets.symmetric(vertical: 30, horizontal: 15),
                                    child: const TextField(
                                      decoration: InputDecoration(
                                        filled: true,
                                        fillColor: Colors.white,
                                        icon: Icon(Icons.person),
                                        border: OutlineInputBorder(),
                                        labelText: 'Username',
                                      ),
                                    )
                                  ),
                                  Container(
                                    margin: const EdgeInsets.only(bottom: 30, left: 15, right: 15),
                                    child: const TextField(
                                      obscureText: true,
                                      decoration: InputDecoration(
                                        filled: true,
                                        fillColor: Colors.white,
                                        icon: Icon(Icons.password),
                                        border: OutlineInputBorder(),
                                        labelText: 'Password',
                                      ),
                                    )
                                  ),
                                  const Spacer(),
                                  Container(
                                    margin: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
                                    padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
                                    child: Row(
                                      mainAxisAlignment: MainAxisAlignment.center,
                                      children: [
                                        const Icon(Icons.login, color: Colors.white,),
                                        const SizedBox(width: 15,),
                                        Text(
                                          AppLocalizations.of(context)!.login,
                                          style: const TextStyle(
                                            fontSize: 22,
                                            color: Colors.white,
                                            fontWeight: FontWeight.bold
                                          ),
                                        )
                                      ],
                                    ),
                                    decoration: BoxDecoration(
                                      color: mainColor,
                                      borderRadius: const BorderRadius.all(Radius.circular(5))
                                    ),
                                  )
                                ],
                              )
                            )
                        ],
                      ),
                      decoration: BoxDecoration(
                        color: Colors.grey[100],
                        border: Border.all(color: Colors.grey[500]!),
                        borderRadius: const BorderRadius.all(Radius.circular(5))
                      )
                    ),
                  )
            ],
          ),
        ),
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          Container(
            margin: const EdgeInsets.all(10),
            height: 82,
            width: 135,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: Image.asset("assets/images/logo-axentya-inv.png").image,
                fit: BoxFit.fill
              )
            ),
          )
        ],
      )
    ],
  ),
);
}

And this is the final result:

My Solution

The problem presents when i click on the TextField and the keyboard shows up going above the TextFields and showing up the black and yellow banner:

Keyboard problem

I don't know why in this screenshot the keyboard doesn't show up, but i swear that is opened.

If i try to put the main Column container inside a SingleChildScrollView, the compiler tells me it cannot render it cause I'm not specifying the height dimensions. How should i fix this.

CodePudding user response:

Add this resizeToAvoidBottomPadding: false to the Scaffold.

 @override
  Widget build(BuildContext context) {
    return Scaffold(
       resizeToAvoidBottomPadding: false,
        body: _createBody(),
       );
  }

EDIT:

If you use de flutter_keyboard_visibility to reduce the logo image when the soft Keyboard is shown would be something like this:

import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';


 @override
  Widget build(BuildContext context) {
    return KeyboardVisibilityBuilder(builder: (context, isKeyboardVisible) {
      return Scaffold(
        resizeToAvoidBottomInset: false,
        body: _createBody(isKeyboardVisible),
      );
    });
  }


Widget _createBody(bool isKeyboardVisible) {
...
       Expanded(
    child: Column(
  children: [
    Container(
      height: isKeyboardVisible ? 50 : 150,  <<--- HERE
      margin: const EdgeInsets.symmetric(
          vertical: 20, horizontal: 10),
      decoration: BoxDecoration(
          shape: BoxShape.circle,
          border:
              Border.all(color: Colors.grey[400]!),
          image: DecorationImage(...
    ),

}

CodePudding user response:

The answer is in the error itself. When the column is inside a view that is scrollable, the column is trying to shrink-wrap its content but since you used Expanded as a child of the column it is working opposite to the column trying to shrink-wrap its children. This is causing this error because these two directives are completely opposite to each other.

As mentioned in the error logs try the following:

Consider setting mainAxisSize to MainAxisSize.min (for column) and using FlexFit.loose fits for the flexible(use Flexible rather than Expanded).

CodePudding user response:

You cannot use Expanded inside SingleChildScrollView. However, you can use CustomScrollView along with SliverFillRemaining widget to achieve that:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverFillRemaining(
            hasScrollBody: false,
            child: _createBody(),
          )
        ],
      ),
    );
  }
  • Related