前言
真的有段时间没写博客了,因为过去的一段时间工作实在是太忙了😅,但忙也有忙的好处,在整个过程中自己的学习也非常快,在忙碌中充实自己,学习一些新的知识。因为刚刚实现了纯Flutter端的IM功能(太TM难了!🤣)在整个实现过程中,把自己对UI方面的一些理解写成blog。今天!给大家隆重介绍,我的气泡家庭🔮,就是你们看见的 微信里balbla~的聊天气泡了。
Show Time
朴实无华 —— 文字气泡 📒
首先就是比较normal,🐳 但又是最重要的,文字气泡,这个气泡,其实不需要太多功能,实用、简洁、准确,就能一把抓住人心,简单的说就是让用户觉得很舒服。先来看看我们的成品吧:
别问我为啥有圆角,因为我们的美工组是这么设计的,有人觉得好看有人觉得丑,但我感觉还可以吧。给大家介绍一下关键点吧,最关键的点就是我们如何控制气泡的宽度和高度,做到文字达到一定长度后自动换行呢 🤔?主角登场——ConstrainedBox,ConstrainedBox是怎样一个Widget呢?顾名思义ConstrainedBox可以给你的Widget加上一些限制,那可太棒了,我们要的效果换个思路其实就是限制气泡的最大宽度,但是我们不限制高度,对吧。所以我们的文字气泡就诞生了🚀
Widget textBubble(String content,Color colors,Color txtColor,double bottomleft,double bottomRight){
return ConstrainedBox(
constraints: BoxConstraints(
maxWidth: 500.w
),
child: Container(
margin: EdgeInsets.only(top: 10.h),
padding: EdgeInsets.symmetric(
horizontal: 34.w,
vertical: 18.h,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(bottomleft), bottomRight: Radius.circular(bottomRight),topRight: Radius.circular(0.0),topLeft: Radius.circular(5.0)),
color: colors,
),
child: Text(content,style: TextStyle(color:txtColor,fontSize: 28.sp),),
),
);
}
复制代码
忽略一些业务数值 📈,来看这个结构,其实我们就是用了一个ConstrainedBox规定了最大宽度,同时定义了四个角的弧度,这两个地方是实现的关键 👀。
细节体现 —— 语音气泡 🔊
语音是聊天中必不可少的一环,部分用户非常喜欢发语音,如果你只是简单的想做一个语音气泡,很简单,把上面文字气泡里的文字替换为一张语音的图片即可,但是你会发现用户体验非常差,你自己都不想用😑。我个人无法接受这样的产品,所以大家可以跟我一起来改进我们的气泡:
播放动画
既然谈到用户体验,动画的播放必不可少,用户点了语音气泡单纯的播放声音,用户不知道点的是哪个气泡,用户感受上非常差 🤨。这个动画往往难倒了许多同学。其实没有这么难,我们有美工啊!大家参考微信或者下面的成品图,思考一下,我们是否有必要自己去画一个动画出来?其实没有必要,我们的喇叭,其实就是三张图片的不停替换罢了 💡。
这样一个语音图片让它动起来 ⛓,我们其实只需要~一个白点的图片、一个白点加圆弧的图片
看吧,三张图片轮流换就是一个动画了呀!实现方案就是我们的定时器 ⏰,用一个定时器没半秒切换一下图片,亲测效果非常nice 👍
_timer = new Timer.periodic(new Duration(milliseconds: 500), (timer) {
if(i == 3)
{
i = 1;
}
else
{
i ++;
}
setState(() {
if(i == 1)
{
_voiceImage = "assets/images/voice_point_right.png";
}
if(i == 2)
{
_voiceImage = "assets/images/voice_step_left.png";
}
if(i == 3)
{
_voiceImage = "assets/images/voice_left.png";
}
});
});
复制代码
气泡长度
其实在用户的交互上还有非常关键的一个小细节,就是这个语音气泡的长度 📐,我们可以自己写一个小算法,让不同的语音时长来控制气泡的长度,这个小的改变会极大的提高页面的美观,这边给大家意思一下,你要控制的气泡宽度,一定要控制最长长度、最短长度,1s 的语音和 100s 的语音很容易让你的长度过长 🕹
double width = 0.0;
width = timeLength * 2 * 20.w;
if(width < 150.w)
{
width = 150.w;
}
if(width > 400.w)
{
width = 400.w;
}
复制代码
最终的我们的语音气泡的效果就是这样了,加上点击动画,真是爱了爱了:
源码
Widget voiceBubble(int timeLength,Color colors,double bottomleft,double bottomRight, String voiceImage){
double width = 0.0;
width = timeLength * 2 * 10.w;
if(width < 150.w)
{
width = 150.w;
}
if(width > 400.w)
{
width = 400.w;
}
return Container(
margin: EdgeInsets.only(top: 10.h),
width: width,
padding: EdgeInsets.symmetric(
horizontal: 34.w,
vertical: 18.h,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(bottomleft), bottomRight: Radius.circular(bottomRight),topRight: Radius.circular(0.0),topLeft: Radius.circular(5.0)),
color: colors,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text((timeLength).toString() + "''",style: TextStyle(color: Colors.white),),
SizedBox(width: 20.w,),
Image.asset(voiceImage,color: Colors.white,width: 24.w),
],
),
);
}
复制代码
老实敦厚 —— 图片气泡 🖼
图片气泡也是我们日常聊天中不可或缺的一环,如何让图片给用户进行展示,接下来我将给大家展示如何做一个fantastic的图片气泡!图片气泡,大家也可以先仔细思考需要注意哪几个点,你作为用户,收到了一条图片消息,你最在意的是什么?是什么?
图片的Size
打开你的相册,翻翻几张照片,你不难发现,除了你用手机相机拍摄的照片,你还会有,从第三方平台下载的,自己剪裁的。那你的气泡也不能固定长宽,需要有强大的动态性。这点的制作我和美工组一起参考了微信的一些方案 🍭。我们给图片规定了最大宽度、最大高度,在这个范围内我们会按照图片本身的大小进行展示,但是超过这个长宽,我们会进行类似压缩,裁切 ✂️ 的操作,让图片看起来尽可能工整。竖向为主的图片依旧保持竖直方向的构图,横向的图片也类似。
图片的展示
图片肯定需要给用户进行更进一步的展示,让用户进行大图的查看 🚠,对吧,如何进行大图的查看,参考市面上大多数app的做法——新启页面!同时,为了把用户体验做到极致,我们还要给界面跳转,新增跳转动画,就是Flutter提供的,非常适合我们业务场景的Hero动画,用于图片的大图展示 🎱。
图片的缩放
既然已经到了图片的展示,我们就还要追求更极致的用户体验,我们还让他能缩放!功能直接通过插件即可实现,熟悉一下API即可,但是要注意缩放比例的限制,我直接参看🍎 Apple的缩放限制,没别的意思,Apple的用户体验无人能及。
最终效果:
源码:
Widget imageBubble(BuildContext context,String url){
final String imgUrl = "";
return GestureDetector(
onTap: (){
Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => HeroPhotoViewRouteWrapper(
url: url,
minScale: 0.1,
maxScale: 1.5,
imageProvider: NetworkImage(
url
)
),
),
);
},
child: Hero(
tag: "${url}",
child: Container(
margin: EdgeInsets.only(top: 10.h),
padding: EdgeInsets.symmetric(
vertical: 10.h,
),
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 300.h,maxWidth: 400.w),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Theme.of(context).brightness == Brightness.light ? Color.fromRGBO(237, 237, 237, 1) : Color.fromRGBO(17, 17, 17, 1),
),
child: ClipRRect(![](https://p9-/tos-cn-i-k3u1fbpfcp/e4fa8e3341974cf688fb2238394bda77~tplv-k3u1fbpfcp-watermark.image)
borderRadius: BorderRadius.circular(10.0),
child: CachedNetworkImage(
imageUrl: url,
placeholder: (context, url) => SizedBox(
width: 100.w,
height: 100.h,
child: Center(
child: LoadingIndicator(indicatorType: Indicator.ballClipRotateMultiple, color: Theme.of(context).brightness == Brightness.light ? Color.fromRGBO(61, 93, 237, 1) : Color.fromRGBO(54, 83, 193, 1),),
),
),
errorWidget: (context, url, error) => new Icon(Icons.error),
),
),
),
),
),
),
);
}
复制代码
结尾
以上就是我给各位介绍的我的一部分气泡 🧽,如果各位有兴趣,我后续还会给大家分享更多的美丽复杂气泡,在整个开发过程中一定要注意用户体验,在用户的角度思考 🔫,有些很简单的功能也会在很大程度上改善用户体验哦。
🐳 欢迎访问我的🔗 github
如果觉得《flutter图片聊天泡泡_Flutter极致的业务封装——各类聊天气泡(一)》对你有帮助,请点赞、收藏,并留下你的观点哦!