[英]How do I clip a variable sized widget in flutter?
I'm building a chat app where audio messages can accompany the text.我正在构建一个聊天应用程序,其中音频消息可以伴随文本。 The widget that displays this is a very standard looking chat bubble (think iMessage) with one twist - the bubble becomes a progress bar when the audio is playing.显示此内容的小部件是一个非常标准的聊天气泡(想想 iMessage),但有一个转折——当音频播放时,气泡变成了一个进度条。 The progress bar is essentially just a gradual change in the background color.进度条本质上只是背景颜色的渐变。 You can see the layout in this dartpad (hit run).您可以在这个dartpad中看到布局(点击运行)。 A screenshot of the mock is here:模拟的屏幕截图在这里:
Because the chat bubble is rounded, I need the progress bar to round only at the end.因为聊天气泡是圆形的,所以我需要进度条只在最后才圆形。 In other words, it should always be rounded on the left as it is flush with the left side of the message but it should be flat on the right until it hits the end of the message.换句话说,它应该总是在左边四舍五入,因为它与消息的左侧齐平,但它应该在右边是平的,直到它到达消息的末尾。 I think ClipRRect
is the right widget to do this.我认为ClipRRect
是执行此操作的正确小部件。
However, because the message bubble width is variable, I use a FractionallySizedBox
as the progress bar.但是,因为消息气泡的宽度是可变的,所以我使用FractionallySizedBox
作为进度条。 1/10th the way through the audio, it should be 1/10th the width of the chat bubble.通过音频的 1/10,应该是聊天气泡宽度的 1/10。 Then I use Positioned.fill
to wrap the progress bar so that the fraction is taken out of the full message bubble width.然后我使用Positioned.fill
包裹进度条,以便从完整的消息气泡宽度中取出分数。 ClipRRect
does not seem to play nicely wrapping Positioned.fill
I believe it expects the child to have a set size: ClipRRect
似乎不能很好地包装Positioned.fill
我相信它希望孩子有一个固定的大小:
RenderBox was not laid out: RenderClipRRect#3b019 relayoutBoundary=up13
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'
This is a dartpad to the version with the not-working ClipRRect
.这是具有不工作ClipRRect
的版本的飞镖板。 Is there some other widget I can wrap Position.fill
in to make it clippable?是否有其他一些小部件可以包装Position.fill
以使其可剪辑? Or maybe a better way to lay this out?或者也许是一种更好的方式来解决这个问题?
Please try the following code.请尝试以下代码。
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: ChatAudioTextBubble("Test message"),
),
),
);
}
}
class ChatAudioTextBubble extends StatefulWidget {
final String text;
ChatAudioTextBubble(this.text);
@override
_ChatAudioTextBubbleState createState() => _ChatAudioTextBubbleState();
}
class _ChatAudioTextBubbleState extends State<ChatAudioTextBubble>
with SingleTickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
lowerBound: 0.0,
upperBound: 1.0,
value: 0.0,
duration: const Duration(milliseconds: 1000),
vsync: this,
)..addListener(() {
this.setState(() {});
});
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _onTapHandler() {
_controller.reset();
_controller.forward(from: 0.0);
}
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
_onTapHandler();
print(
"Plays the audio and starts the animation which takes _controller.value from 0-1");
},
child: Stack(children: [
Positioned.fill(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xFFE6E6E6)),
)),
Container(
constraints: BoxConstraints(
minWidth: 40,
maxWidth: MediaQuery.of(context).size.width * 0.70),
child: _buildTextChild()),
Positioned.fill(
child: ClipRRect(
borderRadius: BorderRadius.only(
topRight: Radius.circular(10.0),
bottomRight: Radius.circular(10.0),
),
child: FractionallySizedBox(
alignment: Alignment.centerLeft,
heightFactor: 1,
widthFactor: _controller == null ? 0 : _controller.value,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Colors.blue.withOpacity(0.3),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.zero,
bottomLeft: Radius.circular(10.0),
bottomRight: Radius.zero,
),
),
),
),
),
),
]));
}
Widget _buildTextChild() {
final color = Colors.black;
return Padding(
padding: EdgeInsets.fromLTRB(16, 8, 16, 8),
child: Text(widget.text, style: TextStyle(color: color, fontSize: 18)));
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.