英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论