Ошибка: LayoutBuilder не поддерживает возврат внутренних размеров.
void showDialogWithLayoutBuilder(){
showDialog(context: context, builder: (context){
return AlertDialog(
content: LayoutBuilder(
builder: (context, constraints){
return Text("Very loooooong text");
},
),
);
});
}
Как заставить это работать? Я не хочу обертывать его, устанавливая жестко закодированные значения height и width. Это минимальный воспроизводимый код реальной проблемы. В реальном случае LayoutBuilder — это пакет под названием AutoSizeText.
Я не понимаю, почему AlertDialog вообще использует IntrinsicWidth. Я проверил код, похоже Dialog его не использует. Мне любопытно, что произойдет, если мы удалим эту оболочку IntrinsicWidth.





Вам нужно обернуть LayoutBuilderRenderBox, который игнорирует внутренние функции, как и LayoutBuilder, но без ошибок и, возможно, без дефектов макета.
AlertDialog использует InstrinsicWidth, чтобы диалог выглядел так, как он есть. В примере вы можете видеть два SizedBox разных размеров, но оба виджета в конечном итоге имеют одинаковую ширину 280, это значение берется из ограничения minWidth в Dialog; в этом макете столбец выберет самую большую minWidth из своих дочерних элементов в качестве ширины для всех из них.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/foundation.dart';
void main() {
if (kDebugMode) {
debugCheckIntrinsicSizes = true;
}
runApp(MaterialApp(home: Home()));
}
class Home extends StatelessWidget {
const Home({super.key});
String get o => List.generate(1000, (i) => 'o').join();
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => showDialog(
context: context,
builder: (_) => AlertDialog(
scrollable: true,
title: const SizedBox(
width: 0.0,
child: Text('Short title'),
),
content: SizedByChild(
child: LayoutBuilder(
builder: (_, __) => SizedBox(
width: double.infinity,
child: Text('Very l${o}ng text'),
),
),
),
),
),
child: const Icon(Icons.add),
),
);
}
}
class SizedByChild extends SingleChildRenderObjectWidget {
const SizedByChild({super.key, super.child});
@override
RenderObject createRenderObject(BuildContext context) => RenderWithChildSize();
}
class RenderWithChildSize extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
@override
void performLayout() {
child?.layout(constraints, parentUsesSize: true);
size = child?.size ?? constraints.smallest;
}
@override
void paint(PaintingContext context, Offset offset) {
if (child != null) {
context.paintChild(child as RenderBox, offset);
}
}
@override
bool hitTest(BoxHitTestResult result, {required Offset position}) {
return child?.hitTest(result, position: position) ?? false;
}
@override
double? computeDistanceToActualBaseline(TextBaseline baseline) {
return child?.getDistanceToActualBaseline(baseline);
}
}
Не могли бы вы объяснить, каковы ограничения/компромиссы этого решения? Особенно эта часть "но без ошибок и возможно без дефектов верстки".
Потому что решение просто обходит проверки. Я не знаю, как LayoutBuilder мог бы сделать плохую разметку, но предполагаю, что есть как минимум один крайний случай. Я пробовал использовать анимированный контейнер, и у меня не возникло никаких проблем, так что это может быть просто выбор разработчиков, чтобы стимулировать использование более качественных/быстрых макетов, как в случае с setState (см. обсуждение дизайна).
Итак, какова цель использования
LayoutBuilder, кроме использования его родительских ограничений для наложения на его дочерний элемент, вы должны обернуть этот текст виджетом поля с ограничениями min^height построителя макета.