RenderFlex children , how to wrap a column of listview and row with column in side singlechildscrollview

44 views Asked by At

In flutter , bodypart I have 2 widget : 1 listview.builder and 1 row that containt 2 column with text inside. But don't know how to use SingleChildScrollView and resizeToAvoidBottomInset: true,

 resizeToAvoidBottomInset: true,
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(10),
        child: Column(children: [
          Expanded(
            child: ListView.builder(
              itemCount: widget.mytable.chitiet.length,
              itemBuilder: (context, index) {
                // kiểm tra món ăn đó có thuộc bàn này ko
                if (widget.mytable.chitiet.isNotEmpty) {
                  return GestureDetector(
                    onTap: () {
                      _showEditPrice(widget.mytable.chitiet[index]);
                    },
                    child: ListTile(
                      contentPadding:
                          const EdgeInsets.only(left: 10, right: 10),
                      leading: Text(
                        '${index + 1}',
                        style: const TextStyle(fontSize: 20),
                      ),
                      title: Text(widget.mytable.chitiet[index].meal.name,
                          style: const TextStyle(fontSize: 18)),
                      subtitle: Text(
                          '${money.format(widget.mytable.chitiet[index].meal.price)} x ${widget.mytable.chitiet[index].quantity} ${availableDonViTinh[widget.mytable.chitiet[index].meal.donViTinh]!.data}\n'
                          'Tổng tiền: ${money.format(widget.mytable.chitiet[index].meal.price * widget.mytable.chitiet[index].quantity)}'),
                      trailing: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          IconButton(
                            icon: const Icon(Icons.add),
                            onPressed: () {
                              setState(() {
                                widget.mytable.chitiet[index].quantity += 1;
                                tongtien = widget.mytable.chitiet.fold<double>(
                                    0, (previousValue, currentvalue) {
                                  return previousValue +
                                      currentvalue.meal.price *
                                          currentvalue.quantity;
                                });
                              });
                            },
                          ),
                          IconButton(
                            icon: const Icon(Icons.remove),
                            onPressed: () {
                              setState(() {
                                widget.mytable.status;

                                var oldChitiet = widget.mytable.chitiet
                                    .firstWhere((element) =>
                                        element.meal.name ==
                                        chitietban[index].meal.name);

                                if (oldChitiet.quantity > 1) {
                                  widget.mytable.chitiet[index].quantity -= 1;
                                } else if (widget
                                        .mytable.chitiet[index].quantity <=
                                    1) {
                                  // do nothing
                                }
                                ;
                                tongtien = widget.mytable.chitiet.fold<double>(
                                    0, (previousValue, currentvalue) {
                                  return previousValue +
                                      currentvalue.meal.price *
                                          currentvalue.quantity;
                                });
                              });
                            },
                          ),
                          IconButton(
                            icon: const Icon(Icons.delete),
                            onPressed: () {
                              setState(() {
                                widget.mytable.status;
                                widget.mytable.chitiet.removeAt(index);
                                tongtien = widget.mytable.chitiet.fold<double>(
                                    0, (previousValue, currentvalue) {
                                  return previousValue +
                                      currentvalue.meal.price *
                                          currentvalue.quantity;
                                });
                              });
                            },
                          )
                        ],
                      ),
                    ),
                  );
                } else {
                  const Center(
                    child: Text('Không có món ăn'),
                  );
                }
              },
            ),
          ),
          Expanded(
            flex: 2,
            child: SizedBox(
              height: MediaQuery.of(context).size.height - 500,
              child: Row(
                children: [
                  // ------------cột trái--------------
                  Expanded(
                    flex: 2,
                    child: Padding(
                      padding: const EdgeInsets.only(top: 10),
                      child: Column(
                        children: [
                          const Expanded(
                              flex: 1,
                              child: Text(
                                'Nhập số % giảm giá',
                                style: TextStyle(fontSize: 16),
                              )),
                          const SizedBox(height: 10),
                          Expanded(
                            flex: 1,
                            child: TextFormField(
                              onChanged: (value) {
                                setState(() {
                                  phantram = tongtien *
                                      double.parse(
                                          discountController.value.text) /
                                      100;
                                });
                              },
                              keyboardType: TextInputType.number,
                              controller: discountController,
                              validator: (value) {
                                if (loaiGiamGia == 'phantram') {
                                  if (int.parse(value!) < 0 ||
                                      int.parse(value!) > 100) {
                                    return 'Giá trị phải nằm trong khoảng từ 0 đến 100';
                                  }
                                } else {
                                  if (int.parse(value!) < 0) {
                                    return 'Hãy nhập số tiền hợp lệ';
                                  }
                                }
                                return null;
                              },
                              decoration: const InputDecoration(
                                contentPadding: EdgeInsets.all(16),
                                hintText: 'Số tiền/ %',
                              ),
                            ),
                          ),
                          Expanded(flex: 1, child: Text(''))
                        ],
                      ),
                    ),
                  ),
                  // ------------cột phải--------------
                  Expanded(
                      flex: 3,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.end,
                        children: [
                          Expanded(
                            flex: 1,
                            child: Text(
                              'Tạm tính: ${money.format(tongtien)} đ',
                              style: const TextStyle(
                                  color: Colors.black, fontSize: 18),
                            ),
                          ),
                          Expanded(
                            flex: 1,
                            child: Text(
                              'Được giảm: ${money.format(phantram + tienmat)} đ',
                              style: const TextStyle(
                                  color: Colors.black, fontSize: 18),
                            ),
                          ),
                          Expanded(
                            child: Text(
                              'Tổng tiền: ${money.format(tongtien - phantram - tienmat)} đ',
                              style: const TextStyle(
                                  color: Colors.black, fontSize: 18),
                            ),
                          ),
                        ],
                      )),
                ],
              ),
            ),
          ),
        ]),
      ),

I had try to put those in expanded() with flex or sizedBox but nothing working. need answer for how to wrap those thing here the error message:

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

There are 2 answers

1
Md. Yeasin Sheikh On

You can't use Expanded inside a scrollable widget. It is trying to consume infinite height for your case. You can use LayoutBuilder for to get the parent height and set on each item. If it is about splitting the view in two and making separate scrollable widget, You can use Column<[Expanded<A>,Expanded<B>]. wrap each A and B with scrollable widget, while A is already having ListView,you can ignore for A. or with LayoutBuilder as current approach

body: LayoutBuilder(
    builder: (context, constraints) => SingleChildScrollView(
      padding: const EdgeInsets.all(10),
      child: Column(
        children: [
          SizedBox(
            height: constraints.maxHeight / 2,
            child: ListView.builder(
              itemCount: 10,
              itemBuilder: (context, index) {
                // kiểm tra món ăn đó có thuộc bàn này ko
                return GestureDetector(
                  onTap: () {},
                  child: Container(
                    height: 50,
                    color: Colors.red,
                    child: Text('data'),
                  ),
                );
              },
            ),
          ),
          SizedBox(
            height: constraints.maxHeight / 2,
            child: Row(
              children: [
                // ------------cột trái--------------
              ],
            ),
          ),
        ],
      ),
    ),
  ),

You may also check CustomScrollView.

0
Abdul Qadir On

Just wrap your top Column into a container and give it a screen height by MediaQuery and good to go

return Scaffold(
  resizeToAvoidBottomInset: true,
  body: SingleChildScrollView(
    padding: const EdgeInsets.all(10),
    child: Container(
      height: MediaQuery.of(context).size.height,
      child: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: mytable.length,
              itemBuilder: (context, index) {
                // kiểm tra món ăn đó có thuộc bàn này ko
                if (mytable.isNotEmpty) {
                  return GestureDetector(
                    onTap: () {},
                    child: ListTile(
                      contentPadding:
                          const EdgeInsets.only(left: 10, right: 10),
                      leading: Text(
                        '${index + 1}',
                        style: const TextStyle(fontSize: 20),
                      ),
                      title: Text("name",
                          style: const TextStyle(fontSize: 18)),
                      subtitle: Text('Tổng'),
                      trailing: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          IconButton(
                            icon: const Icon(Icons.add),
                            onPressed: () {},
                          ),
                          IconButton(
                            icon: const Icon(Icons.remove),
                            onPressed: () {},
                          ),
                          IconButton(
                            icon: const Icon(Icons.delete),
                            onPressed: () {},
                          )
                        ],
                      ),
                    ),
                  );
                } else {
                  const Center(
                    child: Text('Không có món ăn'),
                  );
                }
              },
            ),
          ),
          Expanded(
            flex: 2,
            child: SizedBox(
              height: MediaQuery.of(context).size.height - 500,
              child: Row(
                children: [
                  // ------------cột trái--------------
                  Expanded(
                    flex: 2,
                    child: Padding(
                      padding: const EdgeInsets.only(top: 10),
                      child: Column(
                        children: [
                          const Expanded(
                              flex: 1,
                              child: Text(
                                'Nhập số % giảm giá',
                                style: TextStyle(fontSize: 16),
                              )),
                          const SizedBox(height: 10),
                          Expanded(
                            flex: 1,
                            child: TextFormField(
                              onChanged: (value) {},
                              keyboardType: TextInputType.number,
                              controller: TextEditingController(),
                              validator: (value) {},
                              decoration: const InputDecoration(
                                contentPadding: EdgeInsets.all(16),
                                hintText: 'Số tiền/ %',
                              ),
                            ),
                          ),
                          Expanded(flex: 1, child: Text(''))
                        ],
                      ),
                    ),
                  ),
                  // ------------cột phải--------------
                  Expanded(
                      flex: 3,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.end,
                        children: [
                          Expanded(
                            flex: 1,
                            child: Text(
                              'Tạm ',
                              style: const TextStyle(
                                  color: Colors.black, fontSize: 18),
                            ),
                          ),
                          Expanded(
                            flex: 1,
                            child: Text(
                              'Được giả',
                              style: const TextStyle(
                                  color: Colors.black, fontSize: 18),
                            ),
                          ),
                          Expanded(
                            child: Text(
                              'Tổng tiền:',
                              style: const TextStyle(
                                  color: Colors.black, fontSize: 18),
                            ),
                          ),
                        ],
                      )),
                ],
              ),
            ),
          ),
        ],
      ),
    ),
  ),
);

here is the output