gpt4 book ai didi

Flutter 自定义布局,根据其子级决定小部件的大小

转载 作者:行者123 更新时间:2023-12-03 02:39:58 26 4
gpt4 key购买 nike

understanding constraints文章对于理解布局如何工作非常有用。但是,我无法创建按照那里解释的方式工作的自定义布局。
文章说size是向上流动的,首先我们得到child的size,然后我们可以根据children的size来决定我们自己的size。
好像 CustomSingleChildLayout 是一种与一个 child 一起创建自定义布局的方法。在里面,根据我上面提到的文章,我想得到我 child 的尺寸,然后根据这个决定我自己的尺寸。然而,这似乎是不可能的。 getSize() 方法是用约束调用的,因此我应该根据我从上面收到的约束来决定我的小部件大小。我可以在 getPositionForChild() 中获得 child 的尺寸,但这是在我在 getSize() 中给出我的尺寸后调用的.此时触发重新布局是有意义的,但似乎我不允许从布局系统调用的函数中执行此操作。
所以,问题是,实现自定义布局的最佳方法是什么,约束的布局行为向下流动,尺寸向上流动,如 understanding constraints 中所述。 ?
编辑:这是一些代码来解释我真正想要的。
这是我想要的外观。在这里,我手动提供蓝色方块的宽度和高度。我不想那样做。我希望 child 的大小来确定正方形的大小。我希望大小从文本向上流动,蓝色方块应该决定 max(width, height) 的边长.
https://codepen.io/gazialankus/pen/abdKyVR

import 'package:flutter/material.dart';

class AppRoot extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}

class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: SizedBox(
width: 180,
height: 180,
child: Container(
color: Colors.blue,
child: AspectRatio(
aspectRatio: 1,
child: Text(
"I want to be in a tight square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
),
),
);
}
}

void main() {
runApp(AppRoot());
}

有人建议我可以用 Align 包裹它.我在这里试过了,但是 Align长大。 AlignwidthFactorheightFactor利用 child 的大小,但不能把它变成正方形。去除蓝色 Container没有效果:
https://codepen.io/gazialankus/pen/MWKXvpO
import 'package:flutter/material.dart';

class AppRoot extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}

class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.center,
child: Container(
color: Colors.blue,
child: Text(
"I want to be in a square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
),
);
}
}

void main() {
runApp(AppRoot());
}

我在这里尝试使用 AspectRatio制作正方形,但它不关心 child 的大小,只是成长:
https://codepen.io/gazialankus/pen/KKVevXv
import 'package:flutter/material.dart';

class AppRoot extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}

class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: Align(
alignment: Alignment.center,
child: Container(
color: Colors.blue,
child: AspectRatio(
aspectRatio: 1,
child: Text(
"I want to be in a tight square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
),
),
);
}
}

void main() {
runApp(AppRoot());
}

在这里,我正在尝试进行自定义布局,但我无法使用 child 的尺寸来决定我的尺寸。在收到我 child 的尺寸之前,我必须决定我的尺寸。一旦我知道我 child 的大小,试图强制重新布局会引发异常,这是在代码的末尾。 Codepen 默默地失败了。
https://codepen.io/gazialankus/pen/LYGrjxM
import 'package:flutter/material.dart';

class AppRoot extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}

class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: CustomSingleChildLayout(
delegate: MyDelegate(relayout: ValueNotifier<int>(0)),
child: Text(
"I want to be in a square.",
style: TextStyle(
backgroundColor: Colors.red
),
),
),
),
),
);
}
}


class MyDelegate extends SingleChildLayoutDelegate {
ValueNotifier<int> relayout;
MyDelegate({ this.relayout }) : super(relayout: relayout);

@override
bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
return desiredWidth == 100;
}

@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
print('getConstraintsForChild');
return super.getConstraintsForChild(constraints);
}

double desiredWidth = 300;

@override
Offset getPositionForChild(Size size, Size childSize) {
print('getPositionForChild');
print(size);
print(childSize);
if (size.width > childSize.width) {
desiredWidth = childSize.width;
relayout.value++;
// ^trying to force a relayout
// throws exception, output is given at the bottom in comments
print("RELAYOUT");
}
return super.getPositionForChild(size, childSize);
}

@override
Size getSize(BoxConstraints constraints) {
print('getSize');
return Size(desiredWidth, 100);
}
}

void main() {
runApp(AppRoot());
}

/*
Performing hot reload...
Syncing files to device LG H990...
I/flutter (19850): getSize
I/flutter (19850): getConstraintsForChild
I/flutter (19850): getPositionForChild
I/flutter (19850): Size(300.0, 100.0)
I/flutter (19850): Size(148.0, 16.0)

════════ Exception caught by foundation library ════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for ValueNotifier<int>:
'package:flutter/src/rendering/object.dart': Failed assertion: line 1527 pos 12: '_debugCanPerformMutations': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=BUG.md

When the exception was thrown, this was the stack:
#2 RenderObject.markNeedsLayout (package:flutter/src/rendering/object.dart:1527:12)
#3 RenderBox.markNeedsLayout (package:flutter/src/rendering/box.dart:2053:11)
#4 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:207:21)
#5 ValueNotifier.value= (package:flutter/src/foundation/change_notifier.dart:274:5)
#6 MyDelegate.getPositionForChild (package:m_health/ui/app_root.dart:64:16)
...
The ValueNotifier<int> sending notification was: ValueNotifier<int>#ac2fb(1)
════════════════════════════════════════════════════════════════════════════════════════════════════
Reloaded 2 of 522 libraries in 1,390ms.
I/flutter (19850): RELAYOUT

*/

最佳答案

这应该可以解决您的问题。我们使用 UnconstrainedBox 删除了传递下来的约束。 .我们只需要删除垂直,以便 AspectRatio使用宽度约束。然后我们要求子树根据其内在大小来调整大小。当然,这现在很容易溢出,因为它永远不会换行并始终使用其固有宽度。但是,您可以包装 UnconstrainedBoxFittedBox它永远不会溢出,而是缩放以适应可能小于其内在尺寸的父级。您可能还想尝试在 UnconstrainedBox 上设置轴参数到水平。然后 IntrinsicWidth 将被限制为父宽度。

import 'package:flutter/material.dart';

class AppRoot extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo', // Appears in app switcher
theme: ThemeData(
primaryColor: Colors.grey.shade300,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyPage(),
);
}
}

class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
child: UnconstrainedBox(
child: IntrinsicWidth(
child: Container(
color: Colors.blue,
child: AspectRatio(
aspectRatio: 1,
child: Text(
"I want to be in a tight square.",
style: TextStyle(backgroundColor: Colors.red),
),
),
),
),
),
),
),
);
}
}

void main() {
runApp(AppRoot());
}

关于Flutter 自定义布局,根据其子级决定小部件的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62824061/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com