使用SurfaceView实现飘赞动画
ZanBean类,每个ZanBean都要负责实时更新自己的位置、透明度等数据
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Build; import java.util.Random; public class ZanBean { /** * 心的当前坐标 */ public Point point; /** * 移动动画 */ private ValueAnimator moveAnim; /** * 放大动画 */ private ValueAnimator zoomAnim; /** * 透明度 */ public int alpha = 255;// /** * 心图 */ private Bitmap bitmap; /** * 绘制bitmap的矩阵 用来做缩放和移动的 */ private Matrix matrix = new Matrix(); /** * 缩放系数 */ private float sf = 0; /** * 产生随机数 */ private Random random; public boolean isEnd = false;//是否结束 public ZanBean(Context context, int resId, ZanView zanView) { random = new Random(); bitmap = BitmapFactory.decodeResource(context.getResources(), resId); init(new Point(zanView.getWidth() / 2, zanView.getHeight()- bitmap.getHeight() / 2), new Point((random.nextInt(zanView.getWidth())), 0)); } public ZanBean(Bitmap bitmap, ZanView zanView) { random = new Random(); this.bitmap = bitmap; //为了让在起始坐标点时显示完整 需要减去bitmap.getHeight()/2 init(new Point(zanView.getWidth() / 2, zanView.getHeight() - bitmap.getHeight() / 2), new Point((random.nextInt(zanView.getWidth())), 0)); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void init(final Point startPoint, Point endPoint) { moveAnim = ValueAnimator.ofObject(new BezierEvaluator(new Point(random.nextInt(startPoint.x * 2), Math.abs(endPoint.y - startPoint.y) / 2)), startPoint, endPoint); moveAnim.setDuration(1500); moveAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { point = (Point) animation.getAnimatedValue(); alpha = (int) ((float) point.y / (float) startPoint.y * 255); } }); moveAnim.start(); zoomAnim = ValueAnimator.ofFloat(0, 1f).setDuration(700); zoomAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Float f = (Float) animation.getAnimatedValue(); sf = f.floatValue(); } }); zoomAnim.start(); } // public void pause(){
// if(moveAnim !=null&& moveAnim.isRunning()){
// moveAnim.pause();
// }
// if(zoomAnim !=null&& zoomAnim.isRunning()){
// zoomAnim.pause();
// }
// }
//
// public void resume(){
// if(moveAnim !=null&& moveAnim.isPaused()){
// moveAnim.resume();
// }
// if(zoomAnim !=null&& zoomAnim.isPaused()){
// zoomAnim.resume();
// }
// } public void stop() { if (moveAnim != null) { moveAnim.cancel(); moveAnim = null; } if (zoomAnim != null) { zoomAnim.cancel(); zoomAnim = null; } } /** * 主要绘制函数 */ public void draw(Canvas canvas, Paint p) { if (bitmap != null && alpha > 0) { p.setAlpha(alpha); matrix.setScale(sf, sf, bitmap.getWidth() / 2, bitmap.getHeight() / 2); matrix.postTranslate(point.x - bitmap.getWidth() / 2, point.y - bitmap.getHeight() / 2); canvas.drawBitmap(bitmap, matrix, p); } else { isEnd = true; } } /** * 二次贝塞尔曲线 */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) private class BezierEvaluator implements TypeEvaluator<Point> { private Point centerPoint; public BezierEvaluator(Point centerPoint) { this.centerPoint = centerPoint; } @Override public Point evaluate(float t, Point startValue, Point endValue) { int x = (int) ((1 - t) * (1 - t) * startValue.x + 2 * t * (1 - t) * centerPoint.x + t * t * endValue.x); int y = (int) ((1 - t) * (1 - t) * startValue.y + 2 * t * (1 - t) * centerPoint.y + t * t * endValue.y); return new Point(x, y); } }
}
ZanView代码如下:SurfaceView,不断将ZanBean画到自己的画布上。
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView; import java.util.ArrayList; public class ZanView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder surfaceHolder; /** * 心的个数 */ private ArrayList<ZanBean> zanBeen = new ArrayList<>(); private Paint p; /** * 负责绘制的工作线程 */ private DrawThread drawThread; public ZanView(Context context) { this(context, null); } public ZanView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ZanView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.setZOrderOnTop(true); /**设置画布 背景透明*/ this.getHolder().setFormat(PixelFormat.TRANSLUCENT); surfaceHolder = getHolder(); surfaceHolder.addCallback(this); p = new Paint(); p.setAntiAlias(true); drawThread = new DrawThread(); } /** * 点赞动作 添加心的函数 控制画面最大心的个数 */ public void addZanXin(ZanBean zanBean) { zanBeen.add(zanBean); if (zanBeen.size() > 40) { zanBeen.remove(0); } start(); } @Override public void surfaceCreated(SurfaceHolder holder) { if (drawThread == null) { drawThread = new DrawThread(); } drawThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (drawThread != null) { drawThread.isRun = false; drawThread = null; } } class DrawThread extends Thread { boolean isRun = true; @Override public void run() { super.run(); /**绘制的线程 死循环 不断的跑动*/ while (isRun) { Canvas canvas = null; try { synchronized (surfaceHolder) { canvas = surfaceHolder.lockCanvas(); /**清除画面*/ canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); boolean isEnd = true; /**对所有心进行遍历绘制*/ for (int i = 0; i < zanBeen.size(); i++) { isEnd = zanBeen.get(i).isEnd; zanBeen.get(i).draw(canvas, p); } /**这里做一个性能优化的动作,由于线程是死循环的 在没有心需要的绘制的时候会结束线程*/ if (isEnd) { isRun = false; drawThread = null; } } } catch (Exception e) { e.printStackTrace(); } finally { if (canvas != null) { surfaceHolder.unlockCanvasAndPost(canvas); } } try { /**用于控制绘制帧率*/ Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public void stop() { if (drawThread != null) { // for (int i = 0; i < zanBeen.size(); i++) {
// zanBeen.get(i).pause();
// } for (int i = 0; i < zanBeen.size(); i++) { zanBeen.get(i).stop(); } drawThread.isRun = false; drawThread = null; } } public void start() { if (drawThread == null) {
// for (int i = 0; i < zanBeen.size(); i++) {
// zanBeen.get(i).resume();
// } drawThread = new DrawThread(); drawThread.start(); } }
}
调试
public class TestActivity extends BaseActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_zan); final ZanView zan = (ZanView) findViewById(R.id.zan_view); zan.start(); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ZanBean zanBean = new ZanBean(BitmapFactory.decodeResource(getResources(), R.drawable.ic_default_avatar), zan); zan.addZanXin(zanBean); } }); }
}
使用SurfaceView实现飘赞动画相关推荐
- 水波纹+仿探探卡片滑动+飘赞动画
Android开发UI效果 一.水波纹 二.仿探探滑动卡片 三.飘赞动画 本篇文章主要记录一下开发过程通过网上搜索和本项目需求结合最终实现效果做个记录, 本人比较赖,就不抽demo了,关键代码已贴,仿 ...
- 直播app源代码 直播软件开发Android UI动画 仿直播点赞飘心动画效果
直播app源代码 直播软件开发Android UI动画 仿直播点赞飘心动画效果 一个飘心的小动画,之前看也看到网上有很多轮子,但是感觉不是很符合我的需求,所以自己就凑活凑活搞出来一个,废话不多说先看图 ...
- SurfaceView为什么不能做动画?
目录 Android屏幕绘制流程是什么? SurfaceView为什么不能做动画? TextureView也可以实现视频播放,为什么TextureView可以做动画? Android屏幕绘制流程是什么 ...
- android 飘心动画(直播点赞)效果
前段时间在写直播的时候,需要观众在看直播的时候点赞的效果,在此参照了腾讯大神写的点赞(飘心动画效果).下面是效果图: 1.自定义飘心动画的属性 在attrs.xml 中增加自定义的属性 <!-- ...
- android 飘心动画(直播点赞)效果(二)---贝塞尔曲线的实现
上篇文章 android 飘心动画(直播点赞)效果 只有代码,没有相关的说明.因为我自己也没有看懂,所以参照网上另一篇关于贝塞尔曲线实现 飘心动画的效果,目的就是 便于理解上篇文章代码的思路,然后写个 ...
- HTML5粉色气球飘过动画js特效
下载地址 HTML5粉色气球飘过动画特效是一款html5基于svg绘制一大串粉色的气球空中飘动飞过,页面中间带文字logo. dd:
- android开发 鱼动画,如何使用SurfaceView实现鱼儿游动动画
本文实例为大家分享了使用SurfaceView实现动画的具体代码,供大家参考,具体内容如下 与自定义view绘图进行对比: 1.view绘图没有双缓冲机制,而surfaceview有 2.view绘图 ...
- 2048游戏回顾一:使用SurfaceView创建游戏启动动画
SurfaceView有个很大的好处,就是可以在子线程中绘制UI,其他的View只能在主线程中更新UI,这或多或少给编程增加了些不便.而SurfaceVIew在子线程中可以绘制UI的特性,再加上其可以 ...
- Android UI动画 仿直播点赞飘心动画效果
首先在写之前加上效果图: 第一步我们先导入依赖:allprojects {repositories {..........maven { url 'https://jitpack.io' }} }de ...
最新文章
- 那个曾经为美国NASA开发火星大脑的AI公司,现在和华为合作了
- 机器学习理论入门:第二章 经典监督学习算法-决策树
- vscode 常用插件
- python之print实践
- observer mode - theme change
- JavaOne 2012:掌握Java部署
- 【Tensorflow】Tensorflow 自定义梯度
- Spark SQL运行原理和架构
- 如何给小朋友解释单摆运动_单摆的教案
- 项目人力资源管理重点梳理
- opc 多点位一次性读_如何使用Excel通过OPC访问WinCC的实时数据
- SQL*Loader 和 Data Pump
- 【ubuntu操作系统入门】Ubuntu常用命令大全一
- 不确定性推理——主观贝叶斯方法matlab实现
- 从专业角度分析国内创客教育发展
- 自定义类型:结构体2.0(初阶+进阶)+位段+枚举+联合
- tensor.view().permute()
- git pull 报错 Your local changes would be overwritten by merge. Commit, stash or revert them to procee
- calltransaction弹出新的窗口_SAP刘梦_新浪博客
- Codeforce Round #764 div3
热门文章
- `英语` 2022/8/18
- 郭台铭资产对比马云谁更有钱?两人身价多少亿
- 【倩女幽魂妖魔道】聊斋妖魔道之倩女幽魂单机版一键端源码分享
- BUUCTF【ez_pz_hackover_2016】
- 上号神器扫码教程,常见问题解答
- 信奥一本通-动态规划-例9.2-数字金字塔-方法四-逆推法代码实现
- android键盘广告,android键盘钢琴Lite郑永修改版+去广告
- JAVA SE面试题(全)
- 前端学习笔记 - 用CSS实现一个背景色为红色,半径为200px的圆,并设置不停的上下移动动画
- 视频流解码播放之VLC