我正在学习 Flutter,想做一个Widget
就像内置的一样CircleAvatar
。但是,我希望这种行为是
- 指定图像 (
NetworkImage
)和缩写(即 BB)
- 当图像未加载时,显示缩写
- 如果图像加载,则显示图像并删除缩写
下面的代码可以工作,但是当在聊天演示中使用时,它会随着添加多个我的头像而崩溃。
initState 上的断点表明它总是使用输入的第一个消息文本来调用 - 这不是我所期望的。
当图像“重新加载”时它也会闪烁。看来这些小部件正在以我不理解的方式被重用。
class MyAvatar extends StatefulWidget {
NetworkImage image;
MyAvatar({this.text}) {
debugPrint("MyAvatar " + this.text);
if (text.contains('fun')) {
this.image = new NetworkImage("https://cdn3.iconfinder.com/data/icons/minicons-for-web-sites/24/minicons2-14-512.png");
}
}
final String text;
@override
MyAvatarState createState() {
return new MyAvatarState();
}
}
class MyAvatarState extends State<MyAvatar> {
bool showImage = false;
@override
initState() {
super.initState();
if (widget.image != null) {
var completer = widget.image.load(widget.image);
completer.addListener((info, sync) {
setState(() {
showImage = true;
});
});
}
}
@override
Widget build(BuildContext context) {
return !showImage ? new CircleAvatar(radius: 40.0, child: new Text(widget.text[0]))
: new CircleAvatar(radius: 40.0, backgroundImage: widget.image);
}
}
我仍然遇到问题 - 完整代码
import 'package:flutter/material.dart';
// Modify the ChatScreen class definition to extend StatefulWidget.
class ChatScreen extends StatefulWidget { //modified
ChatScreen() {
debugPrint("ChatScreen - called on hot reload");
}
@override //new
State createState() {
debugPrint("NOT on hot reload");
return new ChatScreenState();
} //new
}
// Add the ChatScreenState class definition in main.dart.
class ChatScreenState extends State<ChatScreen> {
final List<ChatMessage> _messages = <ChatMessage>[];
final TextEditingController _textController = new TextEditingController(); //new
ChatScreenState() {
debugPrint("ChatScreenState - not called on hot reload");
}
@override //new
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Friendlychat")),
body: new Column( //modified
children: <Widget>[ //new
new Flexible( //new
child: new ListView.builder( //new
padding: new EdgeInsets.all(8.0), //new
reverse: true, //new
itemBuilder: (_, int index) => _messages[index], //new
itemCount: _messages.length, //new
) //new
), //new
new Divider(height: 1.0), //new
new Container( //new
decoration: new BoxDecoration(
color: Theme.of(context).cardColor), //new
child: _buildTextComposer(), //modified
), //new
] //new
), //new
);
}
Widget _buildTextComposer() {
return new IconTheme(
data: new IconThemeData(color: Theme
.of(context)
.accentColor),
child:
new Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: new Row(
children: <Widget>[
new Container( //new
margin: new EdgeInsets.symmetric(horizontal: 4.0), //new
child: new IconButton( //new
icon: new Icon(Icons.send),
onPressed: () =>
_handleSubmitted(_textController.text)), //new
),
new Flexible(
child: new TextField(
controller: _textController,
onSubmitted: _handleSubmitted,
decoration: new InputDecoration.collapsed(
hintText: "Send a message"),
)
),
])
)
);
}
void _handleSubmitted(String text) {
_textController.clear();
ChatMessage message = new ChatMessage(text: text);
setState(() {
_messages.insert(0, message);
});
}
}
const String _name = "Hardcoded Name";
class ChatMessage extends StatelessWidget {
ChatMessage({this.text, this.image, this.useImage});
final String text;
final NetworkImage image;
final Map useImage;
@override
Widget build(BuildContext context) {
var use = true; //useImage != null && useImage['use'];
var image = new NetworkImage("https://cdn3.iconfinder.com/data/icons/minicons-for-web-sites/24/minicons2-14-512.png");
if (text.contains('bad')) {
image = new NetworkImage("https://cdn3.iconfinder.com/data/icons/minicons-for-web-sites/24/minicons2-14-512.pngz");
}
return new Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 16.0),
child : new CustomCircleAvatar(initials: text[0], myImage: image)
),
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(_name, style: Theme.of(context).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text),
),
],
),
],
),
);
}
}
class CustomCircleAvatar extends StatefulWidget {
NetworkImage myImage;
String initials;
CustomCircleAvatar({this.myImage, this.initials}) {
debugPrint(initials);
}
@override
_CustomCircleAvatarState createState() => new _CustomCircleAvatarState();
}
class _CustomCircleAvatarState extends State<CustomCircleAvatar>{
bool _checkLoading = true;
@override
void initState() {
if (widget.myImage != null) {
widget.myImage.resolve(new ImageConfiguration()).addListener((image, sync) {
if (mounted && image != null) {
setState(() {
_checkLoading = false;
});
}
});
}
}
@override
Widget build(BuildContext context) {
return _checkLoading == true ? new CircleAvatar(child: new Text(widget.initials))
: new CircleAvatar(backgroundImage: widget.myImage);
}
}
输入“fun”作为消息,然后输入“bad”作为第二条消息 -image https://i.stack.imgur.com/f1Oj6.png这个想法是,根据您输入的内容,可能会加载(或不加载)不同的图像。在“加载失败”的情况下,应保留缩写。