微信Android客户端中表情雨效果的实现
微信android客户端中的表情雨效果在聊天中生动活泼,具体会出现特殊效果的词有恭喜发财、年年有余、想你了、生日快乐、么么哒等等,随着节日来临会有更新词库及图片内容出现。具体效果如下图:
现就其实现过程进行一详细分析。
这个功能可以分为两步走:
第一步是取用服务器词库及表情图片,以及对聊天页面发送的文字的监听,这一点并没有什么要特别注意的,本文略过。
第二步也就是实现表情雨的关键,即UI的展示效果及其中涉及的一系列问题。下面做一简要分析及实现。
从微信表情雨的效果来看,是一张表情图icon以随机位置、随机速度、随机初始时间(皆在指定的范围内)从屏幕顶端向屏幕底端的平移运动,认清了这一点,实现起来逻辑就比较清晰了。按照这一目标,可以自定义一个EmotionsView如下,这里假设使用本地图片drawable/test_icon.png,并设置有20个表情。
public class EmotionsView extends View { // 表情图片
Bitmap bitmap_emotion = null; private boolean isEnd = true; public boolean isEnd() {
return isEnd;
} public void setEnd(boolean isEnd) {
this.isEnd = isEnd;
} private final Paint mPaint = new Paint(); private static final Random RNG = new Random(); private Coordinate[] emotions = new Coordinate[20]; int view_height = 0;
int view_width = 0; private int[] emotionX = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
private int[] emotionY = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
private int[] emotionZ = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; public EmotionsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public EmotionsView(Context context, AttributeSet attrs) {
super(context, attrs); } public void LoadEmotionImage() {
Resources r = this.getContext().getResources();
bitmap_emotion = ((BitmapDrawable) r.getDrawable(R.drawable.test_icon)).getBitmap();
} public void LoadEmotionImage(int intDrawable) {
Resources r = this.getContext().getResources();
bitmap_emotion = ((BitmapDrawable) r.getDrawable(intDrawable)).getBitmap();
} public void setView(int height, int width) {
view_height = height - 100;
view_width = width - 50; } public void clearAllEmotions() {
emotionX = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
emotionY = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
emotionZ = new int[] {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}; } /**
* 随机生成位置
*/
public void addRandomEmotion() {
calculateNextCoordinate();
for (int i = 0; i < 20; i++) {
if (emotions[i] == null) {
emotions[i] = new Coordinate(emotionX[i], emotionY[i]);
} else {
emotions[i].setXY(emotionX[i], emotionY[i]);
}
if (emotionY[i] >= view_height) {
emotions[i] = null;
}
}
} private void calculateNextCoordinate() {
for (int i = 0; i < 20; i++) {
if (emotionX[i] == 0) {
emotionY[i] = RNG.nextInt(1000) - 1000;
emotionX[i] = RNG.nextInt(view_width - 1) + 1;
emotionZ[i] = RNG.nextInt(20) + 10;
}
else {
emotionY[i] += emotionZ[i];
}
}
} private class Coordinate {
public int x;
public int y; public Coordinate(int newX, int newY) {
x = newX;
y = newY;
} public boolean equals(Coordinate other) {
if (x == other.x && y == other.y) {
return true;
}
return false;
} @Override
public String toString() {
return "Coordinate: [" + x + "," + y + "]";
} public void setXY(int x, int y) {
this.x = x;
this.y = y;
}
} @Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isEnd) {
return;
}
boolean temp = true;
for (int x = 0; x < 20; x += 1) {
if (emotions[x] != null && bitmap_emotion != null && !bitmap_emotion.isRecycled()) {
canvas.drawBitmap(bitmap_emotion, ((float) emotions[x].x),
((float) emotions[x].y), mPaint);
temp = false;
}
}
if (temp) {
isEnd = true;
}
}}
并自定义BackgroundView如下:
public class BackgroundView extends View { private static final String TAG = "BackgroundView";
// 屏幕的高度和宽度
int view_height = 0;
int view_width = 0;
Bitmap bmp = null; /**
* 构造器
*/
public BackgroundView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
} public BackgroundView(Context context, AttributeSet attrs) {
super(context, attrs); } /**
* 设置当前窗体的实际高度和宽度
*/
public void SetView(int height, int width) {
view_height = height;
view_width = width;
} public void SetBitmap(Bitmap bitmap) {
bmp = bitmap;
} @SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// MyLog.d(TAG, view_width + " " + view_height);
if (bmp == null) {
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.wish_background);
}
Rect src = new Rect();// 图片
Rect dst = new Rect();// 屏幕位置及尺寸
// src 这个是表示绘画图片的大小
src.left = 0; // 0,0
src.top = 0;
src.right = bmp.getWidth();// mBitDestTop.getWidth();,这个是桌面图的宽度,
src.bottom = bmp.getHeight();// mBitDestTop.getHeight()/2;//
// 这个是桌面图的高度的一半
// 下面的 dst 是表示 绘画这个图片的位置
dst.left = 0; // miDTX,//这个是可以改变的,也就是绘图的起点X位置
dst.top = 0; // mBitQQ.getHeight();//这个是QQ图片的高度。 也就相当于 桌面图片绘画起点的Y坐标
dst.right = view_width; // miDTX + mBitDestTop.getWidth();//
// 表示需绘画的图片的右上角
dst.bottom = view_height; // mBitQQ.getHeight() +
// mBitDestTop.getHeight();//表示需绘画的图片的右下角
canvas.drawBitmap(bmp, src, dst, null);// 这个方法 第一个参数是图片原来的大小,第二个参数是
// 绘画该图片需显示多少。也就是说你想绘画该图片的某一些地方,而不是全部图片,第三个参数表示该图片绘画的位置 src = null;
dst = null;
}
在聊天页面中,编写表情雨动画函数showEmotionsView(),通过一个Handler实现表情动画。节选代码如下:
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if (ev == null || ev.isEnd()) {
return;
}
ev.addRandomEmotion(); ev.invalidate();
sleep(50);
} public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public void update() {
ev.setEnd(false);
ev.clearAllEmotions();
ev.addRandomEmotion();
mRedrawHandler.removeMessages(0);
mRedrawHandler.sleep(200);
} private void showEmotionsView() {
// 获得表情雨视图,加载icon到内存(在布局文件中置入自定义EmotionsView)
ev = (EmotionsView) findViewById(R.id.emotion_view); // 此处可实现表情图片的更替,具体判断来自发送的文本内容
int intDrawable = R.drawable.test_icon2;
ev.LoadEmotionImage(intDrawable);
BV.invalidate();
ev.setVisibility(View.VISIBLE); // 获取当前屏幕的高和宽
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
ev.setView(dm.heightPixels, dm.widthPixels);
update();
}
以该思路实现的表情雨动画在各版本Android中均测试通过,由于采用了读取手机屏幕宽、高,利用随机数计算的办法,妥善解决了屏幕适配的问题,如将问题引申,如表情随着运动有大小闪烁变化,或运动轨迹不仅是y轴竖直平移,均可在此基础上加以改进,给聊天页面增添生动的效果。
微信Android客户端中表情雨效果的实现相关推荐
- 微信Android客户端的ANR监控方案
微信Android客户端的ANR监控方案 微信公众号,WeMobileDev 2021年7月19日发布的 微信Android客户端的ANR监控方案 该方案的所有代码已经在Matrix(https:// ...
- 微信Android客户端的卡顿监控方案
2021.8.1 Matrix 2.0 TraceCanary新增了以下功能 微信Android客户端的卡顿监控方案 https://mp.weixin.qq.com/s/3dubi2GVW_rVF ...
- 微信Android客户端架构演进之路
去年7月,笔者在InfoQ举办的ArchSummit深圳2014的架构师峰会上,分享了微信Android客户端的架构演进史.可以说,这是一个典型的Android应用在从小到大的成长过程中的" ...
- 微信Android客户端架构演进及其对开发流程的影响
微信Android客户端架构演进及其对开发流程的影响 http://www.infoq.com/cn/presentations/android-client-architecture-evoluti ...
- android 判断安装微信,Android开发中判断手机是否安装了QQ或者微信
下面一段代码给大家分享了android中判断手机是否安装了qq或者微信,代码简单易懂,非常不错,具有参考借鉴价值,需要的的朋友参考下吧 public static boolean isWeixinAv ...
- 如何在android客户端中做到自动检查数据更新?,UpdateHelper
软件简介 UpdateHelper 是一个为了简化Android App的迭代升级开发的Android Library,任何一个项目只要引入这个library便集成了在线检查新版本的功能以及下载APK ...
- Android直播中弹幕效果实现
在B站或者其他视频网站看视频时,常常会打开弹幕效果,边看节目边看大家的吐槽.弹幕看起来很有意思,今天我们就来实现一个简单的弹幕效果. 从直观上,弹幕效果就是在一个ViewGroup上增加一些View, ...
- 微信 Android 视频编码爬过的那些坑
[编者按]Android 视频相关的开发,大概一直是整个 Android 生态.以及 Android API 中,最为分裂以及兼容性问题最为突出的一部分,本文从视频编码器的选择和如何对摄像头输出的 Y ...
- 微信android手机中点击大图片会自动放大图片
自己使用的是微信Android客户端,使用img标签的src属性将图片设置好了以后,在微信中调试,点击图片竟然放大,自己没写放大图片的方法,也没有调用wx.previewImage()方法,最后查找, ...
最新文章
- html导入.md文件并渲染,vue 导入.md文件(markdown转HTML)
- java cookie的有效期_Java Web cookie的有效期
- 心电信号去噪(part4)--经验模态分解法(EMD)
- 最简单的c语言的编程题目,编程列入考题
- 知乎超高赞:都有哪些习惯值得长期坚持?
- true,false组合问题
- flutter 输入框限制输入 数字、小数
- java map hashtable_Java的HashMap和HashTable
- FIle类常用工具方法整理(持续更新)
- HTTP常见问题总结
- Python 爬虫---(3)Urllib库使用介绍
- python实现发送免费短信功能
- 其实,API 编程并不难!
- Android xml文件的序列化
- JAVA课程设计(小游戏贪吃蛇)完整源码附素材(三)
- oracle 触发器代码,Oracle触发器实例代码
- 微信公众号订阅号与微信服务号有什么不同
- TestCenter测试管理工具功能详解十五(T)
- 用 python 快速「卡通化」人物头像
- Win7 注册ocx控件 “DllRegisterServer的调用失败,错误代码为0x80040200 ”
热门文章
- 树莓派-- NOOBS安装
- H3C V7 旁挂防火墙静态路由引流
- 怎么让CAD文件中图像单独保存
- QT:QChart设置
- 计算机是人类的好伴侣 作文,书是我们的好伴侣_我和书的故事作文
- 【机器学习知识整理二】处理分类数据、处理文本、处理日期和时间
- 随手记录,idea无法创建class,文件夹没有小圆点
- php中 r,PHP中转义字符 (n r)
- html5颜值测试小游戏,html5毫秒统计测试手指点击速度手机游戏
- (JAVA)支付宝小程序登录相关(authToken获取用户唯一userId、encryptedData解密手机号)