草庐IT

dart - flutter:带有后备文本的 CircleAvatar

coder 2023-07-22 原文

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

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

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

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

最佳答案

您可以通过向 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,);
  }
}

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

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",
              ),
            );
          }),),
        );
      }
    }

关于dart - flutter:带有后备文本的 CircleAvatar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46809189/

有关dart - flutter:带有后备文本的 CircleAvatar的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby-on-rails - 带有 Zeus 的 RSpec 3.1,我应该在 spec_helper 中要求 'rspec/rails' 吗? - 2

    使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做

  3. Ruby:如何使用带有散列的 'send' 方法调用方法? - 2

    假设我有一个类A,里面有一些方法。假设stringmethodName是这些方法之一,我已经知道我想给它什么参数。它们在散列中{'param1'=>value1,'param2'=>value2}所以我有:params={'param1'=>value1,'param2'=>value2}a=A.new()a.send(methodName,value1,value2)#callmethodnamewithbothparams我希望能够通过传递我的哈希以某种方式调用该方法。这可能吗? 最佳答案 确保methodName是一个符号,而

  4. ruby-on-rails - 带有 Pry 的 Rails 控制台 - 2

    当我进入Rails控制台时,我已将pry设置为加载代替irb。我找不到该页面或不记得如何将其恢复为默认行为,因为它似乎干扰了我的Rubymine调试器。有什么建议吗? 最佳答案 我刚发现问题,pry-railsgem。忘记了它的目的是让“railsconsole”打开pry。 关于ruby-on-rails-带有Pry的Rails控制台,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/question

  5. ruby-on-rails - rspec - 我怎样才能让 "pendings"有我的文本而不仅仅是 "No reason given" - 2

    我有这个代码:context"Visitingtheusers#indexpage."dobefore(:each){visitusers_path}subject{page}pending('iii'){shouldhave_no_css('table#users')}pending{shouldhavecontent('Youhavereachedthispageduetoapermissionic错误')}它会导致几个待处理,例如ManagingUsersGivenapractitionerloggedin.Visitingtheusers#indexpage.#Noreason

  6. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

  7. ruby - 如何为 pbcopy 生成富文本链接 - 2

    我一直在玩一个脚本,它在Chrome中获取选定的文本并在Google中查找它,提供四个最佳选择,然后粘贴相关链接。它以不同的格式粘贴,具体取决于当前在Chrome中打开的页面-DokuWiki打开的DokuWiki格式,普通网站的HTML,我想要我的WordPress所见即所得编辑器的富文本。我尝试使用pbpaste-Preferrtf来查看没有其他样式的富文本链接在粘贴板上的样子,但它仍然输出纯文本。在文本编辑中保存文件并进行试验后,我想出了以下内容text=%q|{\rtf1{\field{\*\fldinst{HYPERLINK"URL"}}{\fldrsltTEXT}}}|te

  8. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'

  9. ruby-on-rails - 在 Ruby 或 Rails 中,hash.merge({ :order => 'asc' }) can return a new hash with a new key. 什么可以返回带有已删除键的新散列? - 2

    在Ruby(或Rails)中,我们可以做到new_params=params.merge({:order=>'asc'})现在new_params是一个带有添加键:order的散列。但是是否有一行可以返回带有已删除key的散列?线路new_params=params.delete(:order)不会工作,因为delete方法返回值,仅此而已。我们必须分3步完成吗?tmp_params=paramstmp_params.delete(:order)returntmp_params有没有更好的方法?因为我想做一个new_params=(params[:order].blank?||para

  10. ruby-on-rails - 尝试打开 .gitignore 以在文本编辑器中对其进行编辑,但在 OS X Mountain Lion 上找不到文件位置 - 2

    我使用“newapp_name”创建了一个新的Rails应用程序,我正在尝试编辑.gitignore文件,但在我的应用程序文件夹中找不到它。我在哪里可以找到它?我安装了Git。 最佳答案 .gitignore位于项目的root中,而不是app子目录中。首先打开终端并进入您的目录。您需要使用ls-a来显示stash文件。然后使用打开.gitignore 关于ruby-on-rails-尝试打开.gitignore以在文本编辑器中对其进行编辑,但在OSXMountainLion上找不到文件位

随机推荐