Как сделать так, чтобы контейнер занимал высоту родительского виджета?

#flutter #flutter-layout #flutter-web

Вопрос:

У меня есть макет карты, который выглядит следующим образом:

Расположение

Код для этого он выглядит следующим образом:

 Card(
        color: tap ? Colors.green : Colors.white,
        margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 3.0),
        child: Container(
          child: Row(
            children: [
              **Container(
                height: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
                width: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.only(topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
                  image: DecorationImage(
                      image: NetworkImage(widget.menuItem.image),
                      fit: BoxFit.cover
                  ),
                ),**
              ),
              SizedBox(
                width: 8.0,
              ),
              Expanded(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.baseline,
                      textBaseline: TextBaseline.alphabetic,
                      children: [
                        Text(
                          howManyThere() > 0 ? "${howManyThere()} x " : '',
                          style: addBTNHighlight,
                        ),
                        Expanded(
                          child: Text(
                            widget.menuItem.item_name,
                            overflow: TextOverflow.ellipsis,
                            style: tap ? TitleWhite18Bold : Title18bold,
                          ),
                        ),
                      ],
                    ),
                    Container(
                      child: Text(
                        widget.menuItem.description,
                        //overflow: TextOverflow.ellipsis,
                        style: tap ? SubTitleWhite13 : SubTitle13,
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4.0),
                      child: Text(
                        "£"   num.parse(widget.menuItem.price).toStringAsFixed(2),
                        style: tap ? priceHighlightSelected : priceHighlight,
                      ),
                    ),
                  ],
                ),
              ),
              Column(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Container(
                      padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 6.0),
                      decoration: BoxDecoration(),
                      child: Text("ADD", style: tap ? priceHighlightWhite : addBTNHighlight)),
                ],
              ),
            ],
          ),
        ),
      )
 

Как вы можете видеть, я почти на месте с желаемым макетом, но с одной небольшой проблемой, которую можно увидеть в первом и последнем пункте. Из-за заданной ширины и высоты контейнера изображения он оставляет зазор сверху и снизу.

Я бы хотел, чтобы ширина оставалась прежней, но высота была гибкой и регулировалась в соответствии с высотой самой карты. Возможно ли это?

Когда я удаляю атрибут высоты контейнера с изображением, я получаю пустое пространство изображения

ОБНОВЛЕНИЕ: Я также попробовал LayoutBuilder, но безрезультатно, он выдает исключение «Неправильное использование ParentWidget». Код, который я использовал, выглядит следующим образом:

 Row(
            children: [
              widget.menuItem.image.endsWith('/')
                  ? Container()
                  : **LayoutBuilder(
                builder: (context, constraints){
                  return Container(
                    width: 70.0,
                    height: constraints.minHeight,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.all(Radius.circular(5.0)),
                      image: DecorationImage(
                          image: NetworkImage(widget.menuItem.image),
                          fit: BoxFit.cover
                      ),
                    ),
                  );
                }**
              ),
 

Комментарии:

1. Ваш код невозможно воспроизвести. Вы можете попробовать удалить height:70 и обернуть свой Row IntrinsicHeight виджет внутрь.

2. используйте BoxFit.fitHeight или заполните

Ответ №1:

Попробуйте это :

     Column(
      children: [
        Expanded(
          child: Container(
            width: !widget.menuItem.image.endsWith('/')? 70.0 : 0.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.only(topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
              image: DecorationImage(
                  image: NetworkImage(widget.menuItem.image),
                  fit: BoxFit.cover
              ),
            ),
          ),
        ),
      ],
    ),
 

Комментарии:

1. Таким образом, я получаю всевозможные ошибки рендеринга.

Ответ №2:

Проблема здесь в тексте описания, который переполняет желаемую максимальную высоту. Вы можете попытаться ограничить свое Container свойство с помощью a height: 70.0 или добавить его в свой Text виджет maxLines: 1 .

Комментарии:

1. Спасибо, но это не проблема, это особенность. Описание не должно быть урезано до одной строки.

2. итак, вы хотите изменить размер фотографии до максимальной высоты ?

3. Да, это желание

4. чем если вы позволите height изображению Container помочь вам. С другой стороны, постарайтесь придать double.infinity ценность

5. Хорошо.. хорошо, попробуйте использовать LayoutBuilder : api.flutter.dev/flutter/widgets/LayoutBuilder-class.html и пользоваться maxHeight имуществом

Ответ №3:

LayoutBuilder только дайте вам ограничения, которые родитель передает ребенку, что-то вроде 100 < width < 200, 300 < height < infinity . На данный момент высота всех текстов справа еще не определена, поэтому определить высоту основания изображения на этом основании невозможно.

Один из способов сделать это-назначить key каждому элементу списка, получить высоту элемента после того, как все будет готово, перестроить с фиксированной высотой. Это станет двухпроходным процессом и будет менее эффективным.

Официальное решение этой проблемы заключается IntrinsicHeight в том , что концептуально они делают то же самое, но более оптимизированным способом.

Вот минимальный пример:

 import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: App(),
    ),
  );
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
        itemCount: 10,
        itemBuilder: (context, index) {
          return Card(
            clipBehavior: Clip.antiAliasWithSaveLayer,
            // This is where magic happened
            child: IntrinsicHeight(
              child: Row(
                children: [
                  Container(
                    width: 100,
                    decoration: BoxDecoration(
                      image: DecorationImage(
                        image: NetworkImage('https://cataas.com/cat'),
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
                  Expanded(
                    child: Text(
                      // just put some random text with dynamic height
                      'Textn' * (Random().nextInt(4)   4),
                    ),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }
}
 

Комментарии:

1. @Damandroid «Извините, что это не сработало» вам не поможет.

2. Извините, но я отказался от этого после стольких дней, и изменение стратегии показалось мне лучшим вариантом на данный момент. Теперь я изменил макет.

Ответ №4:

Удалите ограничения по высоте, затем
попробуйте заменить fit: BoxFit.cover на BoxFit.fitHeight или BoxFit.fill .

Ответ №5:

Для того, чтобы заполнить изображение высотой карты, вы можете указать требуемую высоту контейнера и обернуть Image виджет в AspectRatio виджет с ratio 1. Это всегда поможет виджету изображения заполнить высоту родительской карты. Взгляните на приведенный ниже код.

Родительский виджет

 Container(
  margin: EdgeInsets.only(bottom: 12),
  height: 100,
  child: Row(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>[
      AspectRatio(
        aspectRatio: 1,
          child: _pictureWidget(widget.menuItem.image),
        ),
       /// Replace `Container` with the needed widget
       Expanded(child: Container()),
     ],
   ),
 )
 

_pictureWidget

 Widget _picture(String url) {
    return _pictureWidget(
      borderRadius: BorderRadius.only(
          topLeft: Radius.circular(5.0), topRight: Radius.circular(5.0)),
      child: Image.network(
        url != null ? url : "",
        fit: BoxFit.cover,
        loadingBuilder: (BuildContext context, Widget child,
            ImageChunkEvent loadingProgress) {
          if (loadingProgress == null) return child;
          return Center(
            child: CircularProgressIndicator(
              value: loadingProgress.expectedTotalBytes != null
                  ? loadingProgress.cumulativeBytesLoaded /
                      loadingProgress.expectedTotalBytes
                  : null,
            ),
          );
        },
      ),
    );
  }