Search code examples
flutterdynamiccontainersheight

Flutter give a Container a dynamic height (ExpansionTile)


I am trying to implement a review page for products. I trying to show the products images in a expansionTile (see second image). Under the expansionTile I add my buttons.

My problem: To show the expansionTile list I must give the container a fix height. But if I have less images in my list the screen show a white space (second image).

How can I make the container height dynamic to hide the white space?

Here my example:
enter image description here

If I add some pictures my screen looks like this.

How I can hide the white space between list and buttons?

enter image description here

Here my Code:

Container(
                        height: MediaQuery.of(context).size.height * 0.5,
                        width: MediaQuery.of(context).size.width * 0.8,
                        child: ListView(
                          children: [
                            ExpansionTile(
                              title: Text('Pictures'),
                              onExpansionChanged: (value) {
                                setState(
                                  () {},
                                );
                              },
                              children: List<Widget>.generate(
                                _imageList.length,
                                (index) => ListTile(
                                  title: Text(_imageList[0]
                                              .path
                                              .split('/')
                                              .last
                                              .length >
                                          25
                                      ? _imageList[0]
                                              .path
                                              .split('/')
                                              .last
                                              .substring(0, 25) +
                                          '...'
                                      : _imageList[index].path.split('/').last),
                                  trailing: Row(
                                    mainAxisSize: MainAxisSize.min,
                                    children: <Widget>[
                                      IconButton(
                                        icon: Icon(
                                          Icons.delete_outline,
                                          size: 20.0,
                                          color: _selected![index]
                                              ? Colors.red
                                              : Colors.red,
                                        ),
                                        onPressed: () {
                                          setState(() {
                                            _selected![index] =
                                                !_selected![index];
                                            _imageList.removeAt(index);
                                          });
                                        },
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      )

Here my full code:

class ReviewPage1 extends StatefulWidget {
  //passed paramter
  final String _productID;

  ReviewPage1(this._productID, {Key? key}) : super(key: key);

  @override
  _ReviewPage1 createState() => _ReviewPage1(_productID);
}

class _ReviewPage1 extends State<ReviewPage1> {
  ///passed paramter
  final String _productID;

  _ReviewPage1(this._productID);

  //controller
  final TextEditingController _controllerReviewTitle = TextEditingController();
  final TextEditingController _controllerReviewDescription =
      TextEditingController();

  //image
  List<File> _imageList = [];
  var _image;
  var imagePicker;

  //list tile color
  List<bool>? _selected = [];

  //stars
  var rating = 1;

  @override
  void initState() {
    super.initState();
    imagePicker = new ImagePicker();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: customSubAppBar("Create Review", context),
      body: SingleChildScrollView(
        child: Center(
          child: Container(
            width: MediaQuery.of(context).size.width * 0.8,
            child: Column(
              children: [
                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.05,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //text
                Row(
                  children: [
                    customText(
                      'Rate your expreince',
                      Colors.black,
                      20,
                      FontWeight.bold,
                      null,
                    ),
                  ],
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.02,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //stars rating
                Row(
                  children: [
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: List.generate(4, (index) {
                        return GestureDetector(
                            onTap: () {
                              setState(() {
                                // Toggle light when tapped.
                                print('star at index: ' + index.toString());
                                rating = index + 1;
                              });
                            },
                            child: Padding(
                                padding: const EdgeInsets.only(right: 8),
                                child: Icon(
                                  //index < rating ? Icons.star : Icons.star_border,
                                  Icons.star,
                                  size: 30,
                                  color: index < rating
                                      ? Theme.of(context).primaryColor
                                      : Colors.black.withOpacity(0.5),
                                )));
                      }),
                    ),
                    Spacer(),
                  ],
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.08,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //text
                Row(
                  children: [
                    customText(
                      'Review Title',
                      Colors.black,
                      20,
                      FontWeight.bold,
                      null,
                    ),
                  ],
                ),

                //textfield review title
                customDefaultTextField(
                  50,
                  1,
                  TextInputType.text,
                  _controllerReviewTitle,
                  1,
                  false,
                  Colors.black87,
                  Theme.of(context).primaryColor,
                  false,
                  Theme.of(context).primaryColor,
                  0,
                  0,
                  Theme.of(context).primaryColor,
                  0,
                  0,
                  'Title *',
                  'Enter Your Title',
                  Colors.black12,
                  2,
                  0,
                  Theme.of(context).primaryColor,
                  2,
                  0,
                  null,
                  0,
                  0,
                  0,
                  0,
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.08,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //text
                Row(
                  children: [
                    customText(
                      'Write Review',
                      Colors.black,
                      20,
                      FontWeight.bold,
                      null,
                    ),
                  ],
                ),

                //textfield review description
                customDefaultTextField(
                  50,
                  1,
                  TextInputType.text,
                  _controllerReviewDescription,
                  1,
                  false,
                  Colors.black87,
                  Theme.of(context).primaryColor,
                  false,
                  Theme.of(context).primaryColor,
                  0,
                  0,
                  Theme.of(context).primaryColor,
                  0,
                  0,
                  'Write your Expreinces *',
                  'Enter your Expreinces',
                  Colors.black12,
                  2,
                  0,
                  Theme.of(context).primaryColor,
                  2,
                  0,
                  null,
                  0,
                  0,
                  0,
                  0,
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.08,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //text
                Row(
                  children: [
                    customText(
                      'Enter your picture',
                      Colors.black,
                      20,
                      FontWeight.bold,
                      null,
                    ),
                  ],
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.03,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //take image
                GestureDetector(
                  onTap: () async {
                    var source = ImageSource.camera;
                    XFile? image = await imagePicker.pickImage(
                        source: source,
                        imageQuality: 50,
                        preferredCameraDevice: CameraDevice.front);
                    setState(
                      () {
                        _image = File(image!.path);
                        _imageList.add(_image);
                        _selected!.add(false);
                      },
                    );
                  },
                  child: Stack(
                    children: [
                      //icon
                      Container(
                        width: MediaQuery.of(context).size.width * 0.8,
                        height: MediaQuery.of(context).size.height * 0.1,
                        decoration: BoxDecoration(
                            color:
                                Theme.of(context).primaryColor.withOpacity(0.8),
                            borderRadius: BorderRadius.all(Radius.circular(8))),
                        child: Center(
                            child: customIcon(
                                Icons.camera_alt_rounded, Colors.black87, 30)),
                      ),

                      //border
                      Container(
                        width: MediaQuery.of(context).size.width * 0.8,
                        height: MediaQuery.of(context).size.height * 0.1,
                        child: DashedRect(
                          color: Colors.black87,
                          strokeWidth: 2.0,
                          gap: 10.0,
                        ),
                      ),
                    ],
                  ),
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.03,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //show images
                _imageList.length != 0
                    ? //IntrinsicHeight(
                    Container(
                        height: MediaQuery.of(context).size.height * 0.5,
                        width: MediaQuery.of(context).size.width * 0.8,
                        child: ListView(
                          children: [
                            ExpansionTile(
                              title: Text('Pictures'),
                              onExpansionChanged: (value) {
                                setState(
                                  () {},
                                );
                              },
                              children: List<Widget>.generate(
                                _imageList.length,
                                (index) => ListTile(
                                  title: Text(_imageList[0]
                                              .path
                                              .split('/')
                                              .last
                                              .length >
                                          25
                                      ? _imageList[0]
                                              .path
                                              .split('/')
                                              .last
                                              .substring(0, 25) +
                                          '...'
                                      : _imageList[index].path.split('/').last),
                                  trailing: Row(
                                    mainAxisSize: MainAxisSize.min,
                                    children: <Widget>[
                                      IconButton(
                                        icon: Icon(
                                          Icons.delete_outline,
                                          size: 20.0,
                                          color: _selected![index]
                                              ? Colors.red
                                              : Colors.red,
                                        ),
                                        onPressed: () {
                                          setState(() {
                                            _selected![index] =
                                                !_selected![index];
                                            _imageList.removeAt(index);
                                          });
                                        },
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      )
                    //)
                    : Container(),

                //text cancel
                Container(
                  width: MediaQuery.of(context).size.width * 0.8,
                  child: TextButton(
                    child: Text(
                      'Send Review',
                      style: TextStyle(
                          color: Colors.white, fontWeight: FontWeight.bold),
                    ),
                    style: TextButton.styleFrom(
                      primary: Colors.black,
                      backgroundColor: Colors.greenAccent[400],
                      onSurface: Colors.grey,
                    ),
                    onPressed: () {
                      if (_checkInputValuesEmpty(
                              context, _controllerReviewTitle.text, 'title') &&
                          _checkInputValuesEmpty(
                              context,
                              _controllerReviewDescription.text,
                              'description')) {
                        final String _userID =
                            FirebaseAuth.instance.currentUser!.uid;
                        _uploadFile(_userID, _productID, context, _imageList);
                      }
                    },
                  ),
                ),

                //size box
                customSizedBox(
                  MediaQuery.of(context).size.height * 0.01,
                  MediaQuery.of(context).size.width * 0,
                  null,
                ),

                //text send review
                Container(
                  width: MediaQuery.of(context).size.width * 0.8,
                  child: TextButton(
                    child: Text(
                      'Cancel',
                      style: TextStyle(
                          color: Colors.white, fontWeight: FontWeight.bold),
                    ),
                    style: TextButton.styleFrom(
                      primary: Colors.black,
                      backgroundColor: Color.fromRGBO(170, 170, 170, 1),
                      onSurface: Colors.grey,
                    ),
                    onPressed: () async {},
                  ),
                ),
              ],
            ),
          ),
        ),
      ),

      //sidebar
      drawer: CustomSideBar(context),
    );
  }

  //upload review images
  Future _uploadFile(_userID, _productID, context, _imageList) async {
    var downloadURLs = [];

    for (var image in _imageList) {
      String url;
      String postId = DateTime.now().millisecondsSinceEpoch.toString();
      String fileName = 'reviewImage_${_productID}_${postId}';

      Reference ref = FirebaseStorage.instance
          .ref()
          .child("images/review/review_images/" + _productID + '/' + _userID)
          .child(fileName);
      await ref.putFile(image);
      url = fileName;
      downloadURLs.add(url);
    }
    //upload review data
    _addReviewData(_productID, downloadURLs, _userID);
  }

  //add review data in db
  _addReviewData(_productID, downloadURLs, _userID) async {
    final String _userID = FirebaseAuth.instance.currentUser!.uid;

    FirebaseFirestore.instance
        .collection('review')
        .doc('productID_' + _productID)
        .collection("userID_" + _userID)
        .doc('review_data')
        .set({
      'stars': rating,
      'title': _controllerReviewTitle.text,
      'description': _controllerReviewDescription.text,
      'image_url': downloadURLs,
    });
    //Navigator.of(context).pushReplacement(
    //  MaterialPageRoute(builder: (context) => VerifyRegisterEmail()));
  }
}

_checkInputValuesEmpty(context, text, field) {
  if (text.toString().length == 0) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text('Enter text in field ${field}'),
    ));
    return false;
  } else {
    return true;
  }
}

Can I give the container a dynamic height which has always the same height how the listview with my image names?


Solution

  • try find this place and add after Colum mainAxisAlignment: MainAxisAlignment.start,

    @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: customSubAppBar("Create Review", context),
          body: SingleChildScrollView(
            child: Center(
              child: Container(
                width: MediaQuery.of(context).size.width * 0.8,
                child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      crossAxisAlignment: CrossAxisAlignment.start,