likes
comments
collection
share

flutter chat UI again flutter 漂亮聊天UI界面实现

作者站长头像
站长
· 阅读数 38

flutter 漂亮聊天UI界面实现 flutter chat UI

 之前写了一个聊天界面,但是只是花架子,并不能使用,无法点击,无法活动,并且由于时间问题也没有完全完成,右侧的聊天界面没有实现。现在,我准备完成一个比较美观且能使用的聊天界面。

寻找聊天界面模板

 先找一个美观的模板来模仿吧。找模板的标准是简介、美丽、大方、清新。

flutter chat UI again  flutter 漂亮聊天UI界面实现

 这次选的是一个比较简洁的界面,淡蓝色为主色,横向三个大模块排列开来,有设置界面、好友列表、聊天界面,就选定用这个了。

chatUI聊天界面实现

整体分析

 最外层使用横向布局,分别放置三个大组件,每个组件里面使用竖向布局来放置各种按钮、好友列表、聊天界面。每个组件里面的细节我们边实现边学习。

外层框架

 我们先实现最外边的框架。用SelectionArea包裹所有后续组件,实现所有文字可以选定。Selection现在有了官方的正式支持,该功能补全了Flutter长时间存在Selection异常等问题,尤其是在Web框架下经常会有选择文本时与预期的行为不匹配的情况。接着用Row水平布局组件来包裹三大块细分功能组件,代码里先用text组件代替。这样框架就设置好了。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, //去掉右上角debug标识
      theme: ThemeData(
        //主题设置
        primarySwatch: Colors.blue,
      ),
      home: const SelectionArea(
        //子组件支持文字选定 3.3新特性
        child: Scaffold(
          //子组件
          body: MyAppbody(),
        ),
      ),
    );
  }
}

class MyAppbody extends StatelessWidget {
  const MyAppbody({super.key});
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        //水平布局
        children: const <Widget>[
          //子组件
           Expanded(
            flex: 1, //空间占比
            child:  Text("按钮组件"), ),
            
           Expanded(
            flex: 1, //空间占比
            child:  Text("好友列表组件"), ),

           Expanded(
            flex: 3, //空间占比
            child:  Text("聊天框组件"), ),
         
        ],
      ),
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

第一个模块设计

 新建一个fistblock文件夹放置我们的第一个模块代码,实现代码分块抽离。还是先写大框架,外围放置竖向排列组件Column,然后再依次放进去头像模块和设置模块。Column是垂直布局,在Y轴排列,也就是纵轴上的排列方式,可以使其包含的子控件按照垂直方向排列,Column是Widget的容器,存放的是一组Widget,而Container里面一次只能存放一个child。

import 'package:flutter/material.dart';
class FistBlockMain extends StatelessWidget {
  const FistBlockMain({super.key});
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        ////竖直布局
        children: const <Widget>[
          //子组件
           Expanded(
            flex:1, //空间占比
            child:  Text("头像"), 
            ),
            
           Expanded(
            flex: 1, //空间占比
            child:  Text("设置"),
             ),

           Expanded(
            flex:1, //空间占比
            child:  Text("帮助"), 
            ),
         
        ],
      ),
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

头像模块实现

 头像模块我们之前也实现过,现在可以直接拿来用,例子里在线状态小圆点在右上角,这里我们依旧利用Badge实现小圆点,同时圆点位置可以自由设置,我比较习惯放在右下角,当然,你也可以通过设置Badge的position参数改变位置。Badge是flutter的插件,flutter也有很多其他的优秀的插件可以使用,有了插件的帮忙,我们可以很方便的实现各种功能。

class User extends StatelessWidget {
  const User({super.key});
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: Badge(
        //头部部件
        //通知小圆点
        badgeColor: Colors.green, //小圆点颜色
        position: const BadgePosition(
            start: 35, top: 35, end: 0, bottom: 0), //小圆点显示位置
        borderSide:
            const BorderSide(color: Colors.white, width: 1.5), //外层白色圆圈框框
        child: const CircleAvatar(
          //图片圆形剪裁
          radius: 25, //圆形直径,(半径)?
          backgroundColor: Colors.white, //背景颜色设置为白色
          backgroundImage: AssetImage(
            "images/5.jpeg", //图片
          ),
        ),
      ),
      title: const Text(//标题
        "George",
        style: TextStyle(
          fontSize: 15, //字体大小
          fontWeight: FontWeight.bold, //字体加粗
        ),
      ), 
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

第一模块蓝色背景模块实现

 写完头像模块突然想起来,第一模块的蓝色背景还没实现呢,现在来实现一个蓝色的背景。因为是背景,所以应该用层叠Stack组件。背景颜色用Container的decoration来设置,实际使用BoxDecoration实现背景颜色盒子的设置,同时还需要设置阴影。BoxDecoration类提供了多种绘制盒子的方法,这个盒子有边框、主体、阴影组成,盒子的形状可能是圆形或者长方形。如果是长方形,borderRadius属性可以控制边界的圆角大小。

class FistBlockMain extends StatelessWidget {
  const FistBlockMain({super.key});
  @override
  Widget build(BuildContext context) {
    return Stack(children: <Widget>[
      const Backgroud(),
      Column(
        //竖直布局
        children: const <Widget>[
          //子组件
          Expanded(
            flex: 1, //空间占比
            child: User(),
          ),

          Expanded(
            flex: 1, //空间占比
            child: Text("设置"),
          ),
          Expanded(
            flex: 1, //空间占比
            child: Text("帮助"),
          ),
        ],
      ),
    ]);
  }
}

class Backgroud extends StatelessWidget {
  const Backgroud({super.key});
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: const BoxDecoration(
        color: Color.fromARGB(220, 100, 149, 237),
        boxShadow: [
          BoxShadow(
              color: Color.fromARGB(220, 100, 149, 237),
              blurRadius: 30, //阴影模糊程度
              spreadRadius: 1 //阴影扩散程度
              )
        ],
      ),
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

 模板的这个颜色我找了半天也没找到,后来就找个相似的先用着,但是总是看起来没有原来的好看。当个程序员难道还需要懂美术和艺术吗。。。

按钮模块实现

 接着要实现若干带图标的按钮了。模板是一个带图标的按钮,我们用TextButton.icon组件实现。按钮能被选定会影响操作体验,这里使用SelectionContainer是他不能被选中。外层使用Column布局依次放置按钮组件。使用Padding调整间距,是他更好看一些。图标和文字大小都是可以设置的。通过Text组件的TextStyle设置文字的颜色、大小,这里我们使用白色的文字。图标使用Icon组件实现,直接使用Icons.lock_clock内置的icon图标。按钮的onPressed和autofocus需要设置,这样的话点击按钮才会有动画显示。Padding组件再一次使用,这个组件我感觉很好用,可以通过他进一步调整部件的位置,进行美化。

class Buttonblock extends StatelessWidget {
  const Buttonblock({super.key});   
  @override
  Widget build(BuildContext context) {
    return SelectionContainer.disabled(//选定失效
      child: Column(
        children: <Widget>[
          //子组件
          Padding(
            padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
            child: TextButton.icon(
              icon: const Icon(
                size: 22,
                Icons.lock_clock,
                color: Colors.white,
              ), //白色图标
              label: const Text(
                "Timeline",
                style: TextStyle(
                    fontSize: 14, //字体大小
                    fontWeight: FontWeight.bold, //字体加粗
                    color: Colors.white //白色文字
                    ),
              ),
              onPressed: (){},//点击事件
              autofocus: true,
            ),
          ),

          Padding(
            padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
            child: TextButton.icon(
              icon: const Icon(
                size: 22,
                Icons.message,
                color: Colors.white,
              ), //白色图标
              label: const Text(
                "Message",
                style: TextStyle(
                    fontSize: 14, //字体大小
                    fontWeight: FontWeight.bold, //字体加粗
                    color: Colors.white //白色文字
                    ),
              ),
              onPressed: () {
                },
              autofocus: true,
            ),
          ),
        ],
      ),
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

按钮点击弹窗showDialog实现

 是按钮当然需要被点击,点击之后我们可以弹一个窗给用户进行各种操作。这里用showDialog实现弹窗。在TextButton.icon的onPressed下实现一个点击弹窗操作。在Flutter里有很多的弹出框,比如AlertDialog、SimpleDialog,调用函数是showDialog。对话框也是一个UI布局,通常会包含标题、内容,以及一些操作按钮。这里实现一个最简单的对话框,如果有需求可以在这个基础上进行修改。

 Padding(
            padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
            child: TextButton.icon(
              icon: const Icon(
                size: 22,
                Icons.message,
                color: Colors.white,
              ), //白色图标
              label: const Text(
                "Message",
                style: TextStyle(
                    fontSize: 14, //字体大小
                    fontWeight: FontWeight.bold, //字体加粗
                    color: Colors.white //白色文字
                    ),
              ),
              onPressed: () {//点击弹框
                  showDialog<void>(
                    context: context,
                    builder: (BuildContext context) {
                      return SimpleDialog(
                        title: const Text('选择'),
                        children: <Widget>[
                           SimpleDialogOption(
                            child: const Text('选项 1'),
                            onPressed: () {
                              Navigator.of(context).pop();
                            },
                          ),
                           SimpleDialogOption(
                            child: const Text('选项 2'),
                            onPressed: () {//点击事件
                              Navigator.of(context).pop();
                            },
                          ),
                        ],
                      );
                    },
                  ).then((val) {
                  });
                },
              autofocus: true,
            ),
          ),

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

第二个模块设计

 第二个模块是两部分,上边部分是一个在线状态展示区域,下边部分是好友列表,中间有一道分隔线。所以第二部分外层使用Column竖直布局组件,结合Stack组件做一个背景色。Stack可以容纳多个组件,以叠加的方式摆放子组件,后者居上,覆盖上一个组件。Stack也是可以存放一组Widget的组件。

class SecondBlockMain extends StatelessWidget {
  const SecondBlockMain({super.key});
  @override
  Widget build(BuildContext context) {
    return 
          Stack(children: <Widget>[
      const Backgroud(),
      Column(
        //竖直布局
        children: const <Widget>[
          //子组件
          Expanded(
            flex: 1, //空间占比
            child: Text("上边"),
          ),
          Expanded(
            flex:4, //空间占比
            child: Text("下边"),
          ),
        ],
      ),
    ]);
  }
}

第二个模块灰色背景颜色实现

 仔细看第二部分发现也是有背景颜色的和阴影的,只不过很浅,不容易看出来。刚才已经实现了带阴影的背景,稍微改一下颜色就可以了,依旧要结合Stack组件。BoxShadow的两个参数blurRadius和spreadRadius经常使用,其中blurRadius是模糊半径,也就是阴影半径,SpreadRadius是阴影膨胀数值,也就是阴影面积扩大几倍。

class Backgroud extends StatelessWidget {
  const Backgroud({super.key});
  @override
  Widget build(BuildContext context) {
    return Container(
      decoration:  BoxDecoration(
        color: const Color.fromARGB(255, 238, 235, 235).withOpacity(0.6),
        boxShadow:  [
          BoxShadow(
              color: const Color.fromARGB(255, 204, 203, 203).withOpacity(0.5),
              blurRadius: 20, //阴影模糊程度
              spreadRadius: 20 ,//阴影扩散程度
              offset:const Offset(20,20), //阴影y轴偏移量
              )
        ],
      ),
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

在线状态展示区域实现

 本来想着放一个图片在这个位置就好了,这样简单。但是如果拖动界面,改变小大,那么图片就会变形,很不美观。所以利用横向布局组件Row放在外层,里面包裹Badge组件实现小圆点,通过position、badgeColor等组件调整圆点位置和颜色。

class Top extends StatelessWidget {
  const Top({super.key});
  @override
  Widget build(BuildContext context) {
    return Row(children: [
      Expanded(
          flex: 1,
          child: ListTile(
            leading: Padding(
              padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
              child: Badge(
                //小圆点
                badgeColor: Colors.orange, //小圆点颜色
                position: const BadgePosition(
                    start: -70, top: 0, end: 0, bottom: 0), //小圆点显示位置
                borderSide: const BorderSide(
                    color: Colors.white, width: 1.5), //外层白色圆圈框框
                child: const Text(
                  //标题
                  "Family",
                  style: TextStyle(
                      fontSize: 12, //字体大小
                      fontWeight: FontWeight.bold, //字体加粗
                      color: Colors.black),
                ),
              ),
            ),
          )),
      Expanded(
          flex: 1,
          child: ListTile(
            leading: Padding(
              padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
              child: Badge(
                //小圆点
                badgeColor: Colors.cyan, //小圆点颜色
                position: const BadgePosition(
                    start: -70, top: 0, end: 0, bottom: 0), //小圆点显示位置
                borderSide: const BorderSide(
                    color: Colors.white, width: 1.5), //外层白色圆圈框框
                child: const Text(
                  //标题
                  "Friend",
                  style: TextStyle(
                      fontSize: 12, //字体大小
                      fontWeight: FontWeight.bold, //字体加粗
                      color: Colors.black),
                ),
              ),
            ),
          )),
    ]);
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

好友列表实现

 好友列表之前也实现过,这次在以前的基础上修改。我们使用ListView组件实现列表,ListView是最常用的可滚动组件之一,它可以沿一个方向线性排布所有子组件。底层使用Column结合ListTile组件,ListTile结合CircleAvatar可以实现圆形头像效果,同时也可以设置主副标题,设置 focusColor改变鼠标悬停时列表颜色,

List listData = [  {"title": 'First', "imageUrl": "images/1.jpg", "description": '09:15'},  {"title": 'Second', "imageUrl": "images/2.jpg", "description": '13:10'},];

class FriendList extends StatelessWidget {
  const FriendList({super.key});
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: listData.map((value) {//重复生成列表
        return Column(
          children: <Widget>[
            ListTile(
              onTap: (){},
              hoverColor: Colors.black,// 悬停颜色
              focusColor: Colors.white,//聚焦颜色
              autofocus:true,//自动聚焦
                leading: CircleAvatar(//头像
                  backgroundImage: AssetImage(value["imageUrl"]),
                ),
                title: Text(
                  value["title"],
                  style: const TextStyle(
                      fontSize: 25, //字体大小
                      color: Colors.black),
                ),
                subtitle: Text(value["description"])),
            const Padding(
              padding: EdgeInsets.fromLTRB(70, 10, 0, 30),
              child: Text(
                maxLines: 2,
                "There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real!",
                style: TextStyle(
                  fontSize: 12,
                  height: 2, //字体大小
                color: Colors.grey),
              ),
            )
          ],
        );
      }).toList(), //注意这里要转换成列表,因为listView只接受列表
    );
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

第三个模块设计

 现在来第三个模块,聊天界面。分析模板布局,从上到下依次是一个搜索框,分隔线,聊天主界面,输入框,表情、视频、语音工具栏和发送按钮。我们,从上到下把他分成四个小部分来实现,外层使用Column组件。

class ThirdBlockMain extends StatelessWidget {
  const ThirdBlockMain({super.key});
  @override
  Widget build(BuildContext context) {
    return Stack(children: <Widget>[
      Column(
        //竖直布局
        children:  const <Widget>[
          //子组件
         Text("1"),
            Divider(
            height: 0.5,
            indent: 20.0,
            color: Colors.grey,
          ),
          Text("2"),
            Divider(
            height: 0.5,
            indent: 20.0,
            color: Colors.grey,
          ),
          Text("3"),
          Text("4"),
       
        ],
      ),
    ]);
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

搜索框实现

 之前实现过搜索框,直接拿过来改一改。外层添加一个SizedBox组件来控制一下搜索框的大小和位置。

class SearchWidget extends StatefulWidget {

  const SearchWidget(
      {Key? key,
      this.height,
      this.width,
      this.hintText,
      this.onEditingComplete})
      : super(key: key);

  @override
  State<SearchWidget> createState() => _SearchWidgetState();
}

class _SearchWidgetState extends State<SearchWidget> {
  var controller = TextEditingController();
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constrains) {
      return SizedBox(
        width: 400,
        height: 40,
        child: TextField(
        controller: controller, //控制器
        decoration: InputDecoration(
            prefixIcon: const Icon(Icons.search), //头部搜索图标
            filled: true,
            fillColor: Colors.grey.withAlpha(50), // 设置输入框背景色为灰色,并设置透明度
            hintText: "Search people",
            hintStyle: const TextStyle(color: Colors.grey, fontSize: 14),
            contentPadding: const EdgeInsets.only(bottom: 20),
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(15), //圆角边框
              borderSide: BorderSide.none,
            ),
            suffixIcon: IconButton(
              //尾部叉叉图标
              icon: const Icon(
                Icons.close,
                size: 17,
              ),
              onPressed: clearKeywords, //清空操作
              splashColor: Theme.of(context).primaryColor,
            )),
      ),
      );
    });
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

聊天,信息发送界面实现

 因为我的这个并不能真的实现聊天,所以就先放text组件在这把吧,后边再进一步完善。这里简单做一些美化操作,输入框不需要背景颜色,图标需要设置成蓝色,同时调节两个模块的长宽高来适应屏幕。输入框使用TextField,与搜索框使用一致。这里要用到StatefulWidget来完成情况输入框的操作。

class ChatUi extends StatelessWidget {
  const ChatUi({super.key});
  @override
  Widget build(BuildContext context) {
    return const SizedBox(
      width: 100,
      height: 400,
      child: Text(""),
    );
  }
}

class InPutUi extends StatefulWidget {
 
  const InPutUi(
      {Key? key,
      this.height,
      this.width,
      this.hintText,
      this.onEditingComplete})
      : super(key: key);

  @override
  State<InPutUi> createState() => _InPutUi();
}

class _InPutUi extends State<InPutUi> {
  var controller = TextEditingController();
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constrains) {
      return  TextField(
          controller: controller, //控制器
          decoration: InputDecoration(
              filled: true,
              fillColor: Colors.white.withAlpha(50), // 设置输入框背景色为灰色,并设置透明度
              hintText: "Write something...",
              hintStyle: const TextStyle(color: Colors.grey, fontSize: 14),
              contentPadding: const EdgeInsets.only(bottom: 20),
              border: const OutlineInputBorder(
                borderSide: BorderSide.none,
              ),
              suffixIcon: IconButton(
                 color: Colors.blue,
                //尾部叉叉图标
                icon: const Icon(
                  Icons.send,
                  size: 16,
                ),
                onPressed: clearKeywords, //清空操作
                splashColor: Theme.of(context).primaryColor,
              )),
        
      );
    });
  }
}

 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

底部工具界面实现

 最后来实现底部工具栏。外层使用横向布局来依次放入带图标按钮。这里用到IconButton、MaterialButton两种组件来实现按钮,一种是图标按钮,一种是普通按钮,之前已经实现过,拿来就可以用了。外围使用Padding组件进行填充,方便后期调整每个组件的位置,使它更好看一点。


class Bottom extends StatelessWidget {
  const Bottom({super.key});
  @override
  Widget build(BuildContext context) {
    return Row(children: [
      Padding(
        padding: const EdgeInsets.fromLTRB(30, 0, 0, 0),
        child: IconButton(
          icon: const Icon(Icons.mood),
          tooltip: 'click IconButton',
          onPressed: () {},
        ),
      ),
      Padding(
        padding: const EdgeInsets.fromLTRB(580, 20, 0, 22),
        child: MaterialButton(
          height: 35,
          color: Colors.blue,
          onPressed: () {}, //点击事件
          autofocus: true,
          child: const Text(
            'Send',
            style: TextStyle(
                fontSize: 12, //字体大小
                fontWeight: FontWeight.bold, //字体加粗
                color: Colors.white),
          ),
        ),
      ),
    ]);
  }
}


 效果图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

总结

 到这里基本上就完成了, 当然,他是不能实际使用的,因为点击、数据交互等功能还没实现,因为我还不会。后期再边学边写吧。

 模板图:

flutter chat UI again  flutter 漂亮聊天UI界面实现

 完成图: flutter chat UI again  flutter 漂亮聊天UI界面实现  自己实现的与模板还是差距很大的。自己的看起来就没那么美观,我应该去学学美术了,一点艺术细胞都没有。

转载自:https://juejin.cn/post/7232274061283115045
评论
请登录