英文:
Set percentage width recording to parent stack, whose width depends on other child
问题
I am having a Stack with two child elements. The second element is some Text and the first element is a Container with some blue background color. I want to have the height of the Container match the height of the Stack given by the height of the Text-Widget. And the width of my Container should be set dynamically with a percentage of the width of the Stack which also comes from the Text widget.
In other words: I want to build a progress indicator, that I can set dynamically. Altough the width of my parent is not known before build-time. And this width should be givene by the text-child-widget.
How can I achieve that?
英文:
I am having a Stack with two child elements. The second element is some Text and the first element is a Container with some blue background color. I want to have the height of the Container match the height of the Stack given by the height of the Text-Widget. And the width of my Container should be set dynamically with a percentage of the width of the Stack which also comes from the Text widget.
In other words: I want to build a progress indicator, that I can set dynamically. Altough the width of my parent is not known before build-time. And this width should be givene by the text-child-widget.
How can I achieve that?
Stack(
alignment: Alignment.centerLeft,
clipBehavior: Clip.none,
children: [
Container(
width: 50,
height: 20,
color: const Color(0xffa0a4fc),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Text(
"some text",
style: const TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 22,
),
),
),
)
答案1
得分: 1
下面是您要翻译的代码部分:
你需要计算文本宽度:
final TextPainter myTextPainter = TextPainter(
text:
TextSpan(text: myText, style: Theme.of(context).textTheme.labelLarge),
textDirection: TextDirection.ltr,
)..layout(maxWidth: MediaQuery.of(context).size.height, minWidth: 0.0);
final myTextSize = myTextPainter.size;
完整代码供您参考:
import 'package:flutter/material.dart';
class Example extends StatefulWidget {
const Example({super.key});
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
String myText = 'loading.. please wait';
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 3));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final TextPainter myTextPainter = TextPainter(
text:
TextSpan(text: myText, style: Theme.of(context).textTheme.labelLarge),
textDirection: TextDirection.ltr,
)..layout(maxWidth: MediaQuery.of(context).size.height, minWidth: 0.0);
final myTextSize = myTextPainter.size;
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
if (!_animationController.isAnimating) {
setState(() {
myText = 'loading.. please wait';
});
_animationController.reset();
_animationController.forward().then((value) {
setState(() {
myText = 'loading.. completed';
});
});
}
},
child: const Text("Start Animating")),
SizedBox(
width: MediaQuery.of(context).size.width,
height: 10.0,
),
Container(
decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Stack(
fit: StackFit.loose,
children: [
AnimatedBuilder(
animation: _animationController,
builder: (context, _) {
return Container(
color: Colors.blue,
height: myTextSize.height,
width: (_animationController.value * myTextSize.width),
);
}),
Text(
myText,
style: Theme.of(context).textTheme.labelLarge,
)
],
),
),
)
],
);
}
}
请注意,这是您提供的代码的翻译版本。如果您有任何其他问题或需要进一步的帮助,请随时告诉我。
英文:
you need to calculate text width :
final TextPainter myTextPainter = TextPainter(
text:
TextSpan(text: myText, style: Theme.of(context).textTheme.labelLarge),
textDirection: TextDirection.ltr,
)..layout(maxWidth: MediaQuery.of(context).size.height, minWidth: 0.0);
final myTextSize = myTextPainter.size;
full code for your reference :
import 'package:flutter/material.dart';
class Example extends StatefulWidget {
const Example({super.key});
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
String myText = 'loading.. please wait';
@override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 3));
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final TextPainter myTextPainter = TextPainter(
text:
TextSpan(text: myText, style: Theme.of(context).textTheme.labelLarge),
textDirection: TextDirection.ltr,
)..layout(maxWidth: MediaQuery.of(context).size.height, minWidth: 0.0);
final myTextSize = myTextPainter.size;
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
if (!_animationController.isAnimating) {
setState(() {
myText = 'loading.. please wait';
});
_animationController.reset();
_animationController.forward().then((value) {
setState(() {
myText = 'loading.. completed';
});
});
}
},
child: const Text("Start Animating")),
SizedBox(
width: MediaQuery.of(context).size.width,
height: 10.0,
),
Container(
decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Stack(
fit: StackFit.loose,
children: [
AnimatedBuilder(
animation: _animationController,
builder: (context, _) {
return Container(
color: Colors.blue,
height: myTextSize.height,
width: (_animationController.value * myTextSize.width),
);
}),
Text(
myText,
style: Theme.of(context).textTheme.labelLarge,
)
],
),
),
)
],
);
}
}
答案2
得分: 0
根据Stack文档:
> Stack小部件的每个子部件都是定位或非定位的(...). 堆栈会自动调整大小以包含所有非定位的子部件(...). 然后,根据它们的top、right、bottom和left属性,定位的子部件相对于堆栈放置。
因此,在Positioned内部使用FractionallySizedBox,然后让Text确定Stack的大小将起到作用:
Stack(
children: [
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.centerLeft,
widthFactor: factor,
child: ...,
),
),
Text(...),
],
)
在您的情况下,使用TextPainter计算Stack内容的大小也是正确的解决方案,但它有一些缺点:
- 对于内容不仅仅是单个
Text的更复杂情况(如上面的演示),它不起作用。 - 它略微性能较差,因为它需要两次计算
Text的大小。
英文:
Per the Stack documentation:
> Each child of a Stack widget is either positioned or non-positioned (...). The stack sizes itself to contain all the non-positioned children, (...). The positioned children are then placed relative to the stack according to their top, right, bottom, and left properties.
So, using FractionallySizedBox inside Positioned and then having the Text determine the Stack size would do the trick:
Stack(
children: [
Positioned.fill(
child: FractionallySizedBox(
alignment: Alignment.centerLeft,
widthFactor: factor,
child: ...,
),
),
Text(...),
],
)
See a demo on dartpad.dev
Using a TextPainter to calculate size of Stack's contents is also correct solution for your case but it has some drawbacks:
- It won't work for more advanced cases where the content of the loader is something other than just single
Text(as in the demo above). - It's slightly less performant because it needs to calculate
Text's size twice.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论