颤振:带有后备文本的 CircleAvatar

bra*_*dge 6 dart flutter

我正在学习 Flutter 并想制作一个Widget就像内置的CircleAvatar. 但是,我希望这种行为是

  • 指定图像 ( NetworkImage) 和首字母(即 BB)
  • 当图像未加载时,显示首字母
  • 如果图像确实加载,显示图像并删除首字母

以下代码可以正常工作,但在聊天演示中使用时,由于添加了多个 MyAvatar,它会崩溃。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);
  }
}
Run Code Online (Sandbox Code Playgroud)

我还是有问题 - 完整代码

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

输入“fun”作为消息,然后输入“bad”作为第二个 - image 这个想法是,根据您输入的内容,可能会加载(或不加载)不同的图像。在“加载失败”的情况下,首字母应该保留。

azi*_*iza 8

你可以通过添加一个监听器来实现这个功能ImageStream,你可以从ImageConfiguration

在这里,我将相同的数据提供给我,ListView您当然可以通过List在任何类中添加图像和首字母作为字段来自定义它,并ListView.builder改为使用能够按索引循环它们。

在此处输入图片说明

class CustomCircleAvatar extends StatefulWidget {
  NetworkImage myImage;

  String initials;


  CustomCircleAvatar({this.myImage, this.initials});

  @override
  _CustomCircleAvatarState createState() => new _CustomCircleAvatarState();
}

class _CustomCircleAvatarState extends State<CustomCircleAvatar>{

  bool _checkLoading = true;

  @override
  void initState() {
    widget.myImage.resolve(new ImageConfiguration()).addListener((_, __) {
      if (mounted) {
        setState(() {
          _checkLoading = false;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return _checkLoading == true ? new CircleAvatar(
        child: new Text(widget.initials)) : new CircleAvatar(
      backgroundImage: widget.myImage,);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以像这样使用它:

void main() {
  runApp(new MaterialApp (home: new MyApp()));
}

    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => new _MyAppState();
    }

    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(title: new Text("Custom Circle Avatar"),),
          body: new ListView(children: new List.generate(20, (int index) {
            return new Container(
              height: 100.0,
              width: 100.0,
              child: new CustomCircleAvatar(myImage: new NetworkImage(
                  "https://www.doginni.cz/front_path/images/dog_circle.png"),
                initials: "Dog",
              ),
            );
          }),),
        );
      }
    }
Run Code Online (Sandbox Code Playgroud)