仿微信聊天炸“屎”效果!!诶,就是玩!
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仿微信聊天炸“屎”效果!!诶,就是玩!相关的知识,希望对你有一定的参考价值。
参考技术ALong Long Ago,微信8.0更新了一个“炸屎”的新功能,还蛮有新意。
这两天和朋友聊天触发了这个功能,当时心想,诶!这文章素材不就来了吗?!趁着周末时间,赶紧来实现一下。
我们先来看看整体实现的效果:
本篇文章无技术含量,纯属娱乐,纯属娱乐
经过不断试验,反复查看了微信炸💩的效果,基本上可以将其拆解成几个小部分。
效果已经拆解了,技术方面具体实现思路如下:
Im聊天界面很简单,一个Recyclerview,分为左右两个type,根据type值,分别加载左侧和右侧的布局。
这里创建一个实体类ImMsg,用于模拟聊天数据。
当然,聊天界面还需要加上输入框,以及表情栏,这里就不一一展示。
聊天界面搭建完成,接下来就开始进入正题,从扔炸弹开始。
上面已经分析了,扔炸弹的过程其实是一个类似抛物线的过程,从右侧聊天发送出去开始到碰到左侧💩结束。
看到扔炸弹的过程,第一反应就是用贝塞尔曲线来解决炸弹路线的问题,炸弹的行进路线比较简单,这里用二阶贝塞尔曲线就能实现。
我们都知道,要实现二阶贝塞尔曲线,至少得知道两个点的数据,一个是 控制点 ,一个是 终点 的坐标。
从上图就可以基本知道,控制点在开始点和终点中间靠上的位置,这里以屏幕宽和高来做计算,模拟出控制点。
终点同样的道理,以起点为参考值,计算出坐标
有个控制点和终点的坐标,那就开始绘制二阶贝塞尔曲线,实现贝塞尔曲线,android中已经有现成的API,Path中有个 quadTo 方法,只要传入控制点和终点的坐标,即生成贝塞尔曲线路径。
有了path,接下来就是将炸弹按照贝塞尔曲线动起来,这里就需要用到 属性动画 结合 PathMeasure ,让炸弹💣按照路径移动。
微信的炸弹在抛物线的同时,是有个不断翻转的效果。
那我们实现就只需要监听属性动画的更新listener,在监听移动的过程中,设置rotation,使炸弹不断进行翻转。
我们来看效果:
接下来该说的就是炸弹的爆炸效果,这里给出的方案是使用 Lottie 库来加载。微信的爆炸效果还是蛮逼真,找了好久,都没找到相应的素材,这里属实无法模拟。
于是就从 https://lottiefiles.com/ 资源库中找到了一个类似爆炸效果的json文件,结合Lottie实现爆炸的效果。
Lottie的使用也很简单,添加依赖
在layout中添加 LottieAnimationView
在炸弹执行抛物线结束时,开始播放
来看下炸弹结合爆炸的整体效果
当炸弹爆炸后,有一个💩被炸开的效果,如下图。
从微信效果上看,存在7个💩的表情,并且每个表情随机倾斜角度,从爆炸动画那里为起点,由小到大弹出,形成由远及近的效果。
实现的方案是自定义View绘制出7个相同的表情图,利用Math.random随机旋转角度,且7个表情在可控范围内随机摆放。
至于由远及近的效果,就需要对自定义的粑粑View进行缩放动画。
另外,在💩炸开的最后,💩会向下移动并且同时渐变透明,所以在缩放动画后开始平移动画
translation和渐变动画alpha。
最后使用AnimatorSet将动画集合,开始播放。
看看效果。
基本上每个拆解的部分都已经实现,现在开始将IM界面、炸弹抛物线、爆炸效果以及最后的炸开效果合在一起。
最后的最后,实现的效果如下:
在炸弹爆炸的瞬间,用户头像和表情都会有被震到抖动的效果,这里就没实现了,有兴趣的小伙伴可以试试。
好了,本篇文章就到这了。觉得还凑合的,可以给个三连哟!
推荐阅读:
玩会儿Compose,原神主题列表
Compose版来啦!仿自如裸眼3D效果
小程序版聊天室|聊天小程序|仿微信聊天界面小程序
仿微信聊天小程序weChatRoom案例,一款基于微信小程序开发的聊天室实战项目。很早之前就有开发过一个h5版聊天室,最近又在原先思路的基础上开发了个小程序版聊天室,功能效果非常接近微信聊天,实现了消息、表情发送,小程序表情解析,图片、视频上传预览,打赏、红包等微交互场景。整体界面风格及效果挺不错哒。
◆ 先睹为快
◆ 项目中用到的弹窗插件,是自己开发的小程序弹窗组件wcPop:
<!-- <>引入弹窗模板.Start -->
<import src="/utils/component/wcPop/tpl.wxml" />
<template is="popup" data="{{ ...__options }}" />
<!-- <>引入弹窗模板.End -->
◆ 小程序消息记录数据
module.exports = [ { id: "msg1", msgtype: 1, isme: "", avatar: "", author: "", msg: "2019年01月20日 上午11:11", imgsrc: "", videosrc: "" }, //时间提醒 { id: "msg2", msgtype: 2, isme: "", avatar: "", author: "", msg: "当前群聊人数较多,为了信息安全,请注意聊天隐私", imgsrc: "", videosrc: "" }, //公告提醒 { id: "msg3", msgtype: 1, isme: "", avatar: "", author: "", msg: "2019年01月20日 上午11:15", imgsrc: "", videosrc: "" }, //时间提醒 { id: "msg4", msgtype: 3, isme: false, avatar: "../../img/uimg/u__chat-img01.jpg", author: "马总(Alibaba)", msg: "本聊天室每日10:00开22:00关期间请各位会员遵守规则禁止发言,多次警告无效踢出聊天室,永久黑名单禁止进入。", imgsrc: "", videosrc: "" }, //文字消息【别人】 { id: "msg5", msgtype: 3, isme: true, avatar: "../../img/uimg/u__chat-img14.jpg", author: "Nice奈斯", msg: "老板,表示下呗!", imgsrc: "", videosrc: "" }, //文字消息【自己】 { id: "msg6", msgtype: 4, isme: false, avatar: "../../img/uimg/u__chat-img02.jpg", author: "Sweet甜心", msg: "", imgsrc: "http://pic.sc.chinaz.com/files/pic/pic9/201901/hpic523.jpg", videosrc: "" }, //图片消息【别人】 { id: "msg7", msgtype: 3, isme: false, avatar: "../../img/uimg/u__chat-img12.jpg", author: "flower花花", msg: "坐等群主的红包哇!:63:", imgsrc: "", videosrc: "" }, //文字消息-含表情【别人】 { id: "msg8", msgtype: 1, isme: "", avatar: "", author: "", msg: "01月20日 下午14:35", imgsrc: "", videosrc: "" }, //时间提醒 { id: "msg9", msgtype: 3, isme: false, avatar: "../../img/uimg/u__chat-img04.jpg", author: "BBK(小龙哥)", msg: "微信公开课演讲文稿,大家有时间的话可以去看看。:33::33::33:", imgsrc: "", videosrc: "" }, //文字消息-含链接【别人】 { id: "msg10", msgtype: 5, isme: false, avatar: "../../img/uimg/u__chat-img04.jpg", author: "BBK(小龙哥)", msg: "", imgsrc: "http://p3.pstatp.com/large/tos-cn-i-0004/39a6ed910d794ea8a6d85860b3464e82", videosrc: "https://v1-tt.ixigua.com/a69066ac303ccae7a155145000555100/5c4abb6b/video/m/2208ef8c54b15ae4be9babf28a888fe6d2411612e7f20000b9e74fcbf091/?rc=anF0NGx0N25tajMzZzczM0ApQHRAbzU1NTU8MzQzMzU2NDUzNDVvQGgzdSlAZjN1KWRzcmd5a3VyZ3lybHh3Zjo1QC1kYGdfcWowb18tLWEtL3NzLW8jbyM2LjYvMjYtLi8tMTIuNi06I28jOmEtcSM6YHZpXGJmK2BeYmYrXnFsOiMuLl4%3D&vfrom=xgplayer" }, //视频消息【别人】 { id: "msg11", msgtype: 3, isme: true, avatar: "../../img/uimg/u__chat-img14.jpg", author: "Nice奈斯", msg: "优秀!好棒棒呀~~ 向大佬学习。:79:", imgsrc: "", videosrc: "" }, //文字消息-含表情【自己】 { id: "msg12", msgtype: 2, isme: "", avatar: "", author: "", msg: "\'Luci(王巧巧)\' 撤回了一条消息", imgsrc: "", videosrc: "" }, //公告提醒 { id: "msg13", msgtype: 4, isme: false, avatar: "../../img/uimg/u__chat-img11.jpg", author: "Luci(王巧巧)", msg: "", imgsrc: "http://y3.ifengimg.com/bbc8b9401db0d57e/2014/0721/rdn_53ccd985694da.gif", videosrc: "" }, //图片消息【别人】 { id: "msg14", msgtype: 5, isme: true, avatar: "../../img/uimg/u__chat-img14.jpg", author: "Nice奈斯", msg: "", imgsrc: "http://pic.rmb.bdstatic.com/mvideo/70a0790d49998653eb2deb1cadfbdf93", videosrc: "https://vd3.bdstatic.com/mda-ik6254k2dwqi75zr/mda-ik6254k2dwqi75zr.mp4" }, //视频消息【自己】 { id: "msg15", msgtype: 6, isme: false, avatar: "../../img/uimg/u__chat-img03.jpg", author: "科比", msg: "", imgsrc: "../../img/emotion/face04/0.gif", videosrc: "" }, //文字消息-含大表情【别人】 { id: "msg16", msgtype: 3, isme: true, avatar: "../../img/uimg/u__chat-img14.jpg", author: "Nice奈斯", msg: "哈哈哈~~~ 能不能好好聊天,太TM搞笑了,真是笑屎我了。:28:", imgsrc: "", videosrc: "" }, //文字消息-含表情【自己】 ];
◆ 聊天页面数据处理
// pages/groupChat/groupChat.js var util = require(\'../../utils/util.js\'); import { wcPop } from \'../../utils/component/wcPop/tpl.js\'; const emotions = require(\'./emotion-mock-data.js\'); const messages = require(\'./chat.mock-data.js\'); var emojParse = require(\'./emojParse.js\'); Page({ /** * 页面的初始数据 */ data: { cursorSpacing: 15, //光标与键盘的距离 toView: "scrollBottom", //定位到聊天底部 isEditorFocus: false, //编辑器获取焦点 isEditorPreview: false, //编辑器消息预览 // 消息记录 __messages: messages, // 表情集合 __emotions: emotions.list, // 预览图片地址 previewImgList: [], }, onLaunch: function(){ // ... }, onLoad: function () { // 初始化解析表情 emojParse.init(this, ":_/"); // 解析消息记录里面的表情符号 var _messages = this.data.__messages; for (var i = 0, len = _messages.length; i < len; i++) { // 解析含表情的消息 if (_messages[i].msgtype == 3){ // 解析消息记录表情字符串 _messages[i].msg = { emojiTextArray: emojParse.transEmojStr(_messages[i].msg)}; } } this.setData({ __messages: _messages }); }, /** * 聊天页面JS功能模块------------------------------------------------- */ // 滚动聊天底部 bindToMsgBottom: function (e) { var that = this; setTimeout(function(){that.setData({ toView: "scrollBottom" });}, e ? 100 : 0); }, // 点击聊天面板区域 bindTapMsgPanel: function (e) { this.setData({ isShowChoosePanel: false }); }, // 表情/选择区切换 bindSwtEmotion: function (e) { var that = this; this.setData({ isShowChoosePanel: true, isShowEmotion: true, isShowChoose: false, }); // 滚动到聊天底部 this.bindToMsgBottom(); }, bindSwtChoose: function (e) { var that = this; this.setData({ isShowChoosePanel: true, isShowEmotion: false, isShowChoose: true, }); // 滚动到聊天底部 this.bindToMsgBottom(); }, // 底部多表情切换 bindSwtEmotionBar: function(e) { var idx = e.currentTarget.dataset.index; var _lists = this.data.__emotions; for (var i = 0, len = _lists.length; i < len; i++){ _lists[i].selected = false; } _lists[idx].selected = true; this.setData({ __emotions: _lists }); }, // 点击大图 bindGifImageTap: function (e) { wx.showLoading({title: \'发送中...\',}); var that = this; var _messages = this.data.__messages; var _len = _messages.length; var gifpath = e.currentTarget.dataset.path; // 消息队列 var _data = { id: `msg${++_len}`, msgtype: 6, //大表情 isme: true, avatar: "../../img/uimg/u__chat-img14.jpg", author: "Nice奈斯", msg: "", imgsrc: gifpath, videosrc: "" }; _messages = _messages.concat(_data); this.setData({ __messages: _messages }); setTimeout(function () { wx.hideLoading(); }, 100); // 滚动到聊天底部 this.bindToMsgBottom(true); }, // 选择图片 bindChooseImage: function (e) { var that = this; var _messages = this.data.__messages; var _len = _messages.length; // 消息队列 var _data = { id: `msg${++_len}`, msgtype: 4, //发送图片 isme: true, avatar: "../../img/uimg/u__chat-img14.jpg", author: "Nice奈斯", msg: "", imgsrc: "", videosrc: "" }; wx.chooseImage({ count: 1, success: function(res) { // console.log(res); // console.log(res.tempFilePaths); _data.imgsrc = res.tempFilePaths.toString(); //把单张数组格式图片转换为字符串格式 _messages = _messages.concat(_data); that.setData({ __messages: _messages }); // 滚动到聊天底部 that.bindToMsgBottom(true); }, }) }, // 预览图片 bindPreviewImage: function (e) { // 遍历所有当前聊天记录图片 var _src = e.currentTarget.dataset.src; var _messages = this.data.__messages; var _imglist = this.data.previewImgList; for (var i = 0, len = _messages.length; i < len; i++) { if (_messages[i].imgsrc != "" && _messages[i].msgtype == 4) { if (_imglist.indexOf(_messages[i].imgsrc) == -1) { _imglist.push(_messages[i].imgsrc); } } } // preview images wx.previewImage({ current: _src, urls: _imglist, }) }, // 预览视频 bindPreviewVideo: function (e) { var _id = e.currentTarget.dataset.id; this.playContext = wx.createVideoContext("video_" + _id, this); this.playContext.play(); this.playContext.requestFullScreen({ direction: 0 }); }, // 全屏事件 bindFullscreenchange: function (e) { var _id = e.currentTarget.dataset.id; this.fullchangeContext = wx.createVideoContext("video_" + _id, this); if (e.detail.fullscreen == false){ this.fullchangeContext.pause(); this.fullchangeContext.exitFullScreen(); } }, // 视频播放结束 bindEndedVideo: function (e) { var _id = e.currentTarget.dataset.id; this.stopContext = wx.createVideoContext("video_" + _id, this); this.stopContext.stop(); this.stopContext.exitFullScreen(); }, // 打赏 bindDashang: function (e) { var dsIdx = wcPop({ skin: \'android\', content: [\'wc__tmpl_dashang\'], xclose: true, shadeClose: false, style: \'background: #f3f3f3;\', }); }, // 发送红包 bindHongbao: function (e) { var hbIdx = wcPop({ skin: \'android\', content: [\'wc__tmpl_hongbao\'], xclose: true, shadeClose: false, style: \'background: #f3f3f3;\', }); }, })
以上是关于仿微信聊天炸“屎”效果!!诶,就是玩!的主要内容,如果未能解决你的问题,请参考以下文章