Android实现红包雨动画效果
程序员文章站
2022-05-17 22:34:30
本文介绍了android实现红包雨动画效果,分享给大家,希望对大家有帮助
红包雨
关于实现上面红包雨效果步骤如下:
1.创建一个红包实体类
publ...
本文介绍了android实现红包雨动画效果,分享给大家,希望对大家有帮助
红包雨
关于实现上面红包雨效果步骤如下:
1.创建一个红包实体类
public class redpacket { public float x, y; public float rotation; public float speed; public float rotationspeed; public int width, height; public bitmap bitmap; public int money; public boolean isrealred; public redpacket(context context, bitmap originalbitmap, int speed, float maxsize, float minsize, int viewwidth) { //获取一个显示红包大小的倍数 double widthrandom = math.random(); if (widthrandom < minsize || widthrandom > maxsize) { widthrandom = maxsize; } //红包的宽度 width = (int) (originalbitmap.getwidth() * widthrandom); //红包的高度 height = width * originalbitmap.getheight() / originalbitmap.getwidth(); int mwidth = (viewwidth == 0) ? context.getresources().getdisplaymetrics().widthpixels : viewwidth; //生成红包bitmap bitmap = bitmap.createscaledbitmap(originalbitmap, width, height, true); originalbitmap.recycle(); random random = new random(); //红包起始位置x:[0,mwidth-width] int rx = random.nextint(mwidth) - width; x = rx <= 0 ? 0 : rx; //红包起始位置y y = -height; //初始化该红包的下落速度 this.speed = speed + (float) math.random() * 1000; //初始化该红包的初始旋转角度 rotation = (float) math.random() * 180 - 90; //初始化该红包的旋转速度 rotationspeed = (float) math.random() * 90 - 45; //初始化是否为中奖红包 isrealred = isrealredpacket(); } /** * 判断当前点是否包含在区域内 */ public boolean iscontains(float x, float y) { //稍微扩大下点击的区域 return this.x-50 < x && this.x +50 + width > x && this.y-50 < y && this.y+50 + height > y; } /** * 随机 是否为中奖红包 */ public boolean isrealredpacket() { random random = new random(); int num = random.nextint(10) + 1; //如果[1,10]随机出的数字是2的倍数 为中奖红包 if (num % 2 == 0) { money = num*2;//中奖金额 return true; } return false; } /** * 回收图片 */ public void recycle() { if (bitmap!= null && !bitmap.isrecycled()){ bitmap.recycle(); } } }
上面就红包实体类的源码,重点就是在创建红包实体的时候,初始化红包相关的值,如生成红包图片,图片的宽高,红包初始位置,下落速度等。比较简单。
2.自定义红包雨view
view初始化
public redpackettest(context context, @nullable attributeset attrs) { super(context, attrs); final typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.redpacketstyle); //获取xml中配置的view的style属性,如下落红包数量,下落的基础速度,以及红包图片的最大最小范围 count = typedarray.getint(r.styleable.redpacketstyle_count, 20); speed = typedarray.getint(r.styleable.redpacketstyle_speed, 20); minsize = typedarray.getfloat(r.styleable.redpacketstyle_min_size, 0.5f); maxsize = typedarray.getfloat(r.styleable.redpacketstyle_max_size, 1.2f); typedarray.recycle(); init(); } /** * 初始化 */ private void init() { //初始化画笔 paint = new paint(); paint.setfilterbitmap(true); paint.setdither(true); paint.setantialias(true); //创建一个属性动画,通过属性动画来控制刷新红包下落的位置 animator = valueanimator.offloat(0, 1); //绘制view开启硬件加速 setlayertype(view.layer_type_hardware, null); //初始化属性动画 initanimator(); } private void initanimator() { //每次动画更新的时候,更新红包下落的坐标值 animator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { long nowtime = system.currenttimemillis(); //获取两次动画更新之间的时间,以此来计算下落的高度 float secs = (float) (nowtime - prevtime) / 1000f; prevtime = nowtime; for (int i = 0; i < redpacketlist.size(); ++i) { redpacket redpacket = redpacketlist.get(i); //更新红包的下落的位置y redpacket.y += (redpacket.speed * secs); //如果y坐标大于view的高度 说明划出屏幕,y重新设置起始位置,以及中奖属性 if (redpacket.y > getheight()) { redpacket.y = 0 - redpacket.height; redpacket.isrealred = redpacket.isrealredpacket(); } //更新红包的旋转的角度 redpacket.rotation = redpacket.rotation + (redpacket.rotationspeed * secs); } //重绘 invalidate(); } }); //属性动画无限循环 animator.setrepeatcount(valueanimator.infinite); //属性值线性变换 animator.setinterpolator(new linearinterpolator()); animator.setduration(0); }
view绘制
@override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); //获取自定义view的宽度 mwidth = getmeasuredwidth(); } @override protected void ondraw(final canvas canvas) { //遍历红包数组,绘制红包 for (int i = 0; i < redpacketlist.size(); i++) { redpacket redpacket = redpacketlist.get(i); //将红包旋转redpacket.rotation角度后 移动到(redpacket.x,redpacket.y)进行绘制红包 matrix m = new matrix(); m.settranslate(-redpacket.width / 2, -redpacket.height / 2); m.postrotate(redpacket.rotation); m.posttranslate(redpacket.width / 2 + redpacket.x, redpacket.height / 2 + redpacket.y); //绘制红包 canvas.drawbitmap(redpacket.bitmap, m, paint); } }
红包雨动画开始结束
/** *停止动画 */ public void stoprainnow() { //清空红包数据 clear(); //重绘 invalidate(); //动画取消 animator.cancel(); } /** * 开始动画 */ public void startrain() { //清空红包数据 clear(); //添加红包 setredpacketcount(count); prevtime = system.currenttimemillis(); //动画开始 animator.start(); } public void setredpacketcount(int count) { if (mimgids == null || mimgids.length == 0) return; for (int i = 0; i < count; ++i) { //获取红包原始图片 bitmap originalbitmap = bitmapfactory.decoderesource(getresources(), mimgids[0]); //生成红包实体类 redpacket redpacket = new redpacket(getcontext(), originalbitmap, speed,maxsize,minsize,mwidth); //添加进入红包数组 redpacketlist.add(redpacket); } } /** * 暂停红包雨 */ public void pauserain() { animator.cancel(); } /** * 重新开始 */ public void restartrain() { animator.start(); } /** * 清空红包数据,并回收红包中的bitmap */ private void clear() { for (redpacket redpacket :redpacketlist) { redpacket.recycle(); } redpacketlist.clear(); }
红包点击事件
@override public boolean ontouchevent(motionevent motionevent) { switch (motionevent.getaction()){ case motionevent.action_down: //根据点击的坐标点,判断是否点击在红包的区域 redpacket redpacket = isredpacketclick(motionevent.getx(), motionevent.gety()); if (redpacket != null) { //如果点击在红包上,重新设置起始位置,以及中奖属性 redpacket.y = 0 - redpacket.height; redpacket.isrealred = redpacket.isrealredpacket(); if (onredpacketclicklistener != null) { onredpacketclicklistener.onredpacketclicklistener(redpacket); } } break; case motionevent.action_move: break; case motionevent.action_cancel: case motionevent.action_up: break; } return true; } //根据点击坐标点,遍历红包数组,看是否点击在红包上 private redpacket isredpacketclick(float x, float y) { for (int i = redpacketlist.size() - 1; i >= 0; i --) { if (redpacketlist.get(i).iscontains(x, y)) { return redpacketlist.get(i); } } return null; }
关于自定义红包雨view的主要代码以及分析基本完成了。下面是自定义view的使用。
3.自定义view的使用
红包雨activity
public class redpacketactivity extends appcompatactivity implements view.onclicklistener { private redpackettest redrainview1; private button start, stop; private textview money; private int totalmoney = 0; alertdialog.builder ab; @override protected void oncreate(@nullable bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.red_rain); ab = new alertdialog.builder(redpacketactivity.this); start = (button) findviewbyid(r.id.start); stop = (button) findviewbyid(r.id.stop); money = (textview) findviewbyid(r.id.money); redrainview1 = (redpackettest) findviewbyid(r.id.red_packets_view1); start.setonclicklistener(this); stop.setonclicklistener(this); } @override public void onclick(view v) { if (v.getid() == r.id.start) { startredrain(); } else if (v.getid() == r.id.stop) { stopredrain(); } } /** * 开始下红包雨 */ private void startredrain() { redrainview1.startrain(); redrainview1.setonredpacketclicklistener(new redpackettest.onredpacketclicklistener() { @override public void onredpacketclicklistener(redpacket redpacket) { redrainview1.pauserain(); ab.setcancelable(false); ab.settitle("红包提醒"); ab.setnegativebutton("继续抢红包", new dialoginterface.onclicklistener() { @override public void onclick(dialoginterface dialog, int which) { redrainview1.restartrain(); } }); if (redpacket.isrealred) { ab.setmessage("恭喜你,抢到了" + redpacket.money + "元!"); totalmoney += redpacket.money; money.settext("中奖金额: " + totalmoney); } else { ab.setmessage("很遗憾,下次继续努力!"); } redrainview1.post(new runnable() { @override public void run() { ab.show(); } }); } }); } /** * 停止下红包雨 */ private void stopredrain() { totalmoney = 0;//金额清零 redrainview1.stoprainnow(); }
红包雨activity的xml
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#80000000"> <imageview android:layout_width="match_parent" android:layout_height="match_parent" android:scaletype="fitxy" android:src="@drawable/red_packets_bg" /> <button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始" /> <button android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentright="true" android:text="结束" /> <textview android:id="@+id/money" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerhorizontal="true" android:text="中奖金额:" android:textsize="18sp" android:layout_margintop="10dp" /> <com.example.test.redpacketrain.redpackettest android:id="@+id/red_packets_view1" android:layout_width="match_parent" android:layout_height="match_parent" app:count="20" app:max_size="0.8" app:min_size="0.6" app:speed="500" /> </relativelayout>
自定义view的styleable
<resources> <declare-styleable name="redpacketstyle"> <attr name="count" format="integer" /> <attr name="speed" format="integer" /> <attr name="max_size" format="float" /> <attr name="min_size" format="float" /> </declare-styleable> </resources>
完整的自定义view代码
public class redpackettest extends view { private int[] mimgids = new int[]{ r.drawable.red_packets_icon };//红包图片 private int count;//红包数量 private int speed;//下落速度 private float maxsize;//红包大小的范围 private float minsize;//红包大小的范围 private int mwidth;//view宽度 private valueanimator animator;//属性动画,用该动画来不断改变红包下落的坐标值 private paint paint;//画笔 private long prevtime; private arraylist<redpacket> redpacketlist = new arraylist<>();//红包数组 public redpackettest(context context) { super(context); init(); } public redpackettest(context context, @nullable attributeset attrs) { super(context, attrs); final typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.redpacketstyle); count = typedarray.getint(r.styleable.redpacketstyle_count, 20); speed = typedarray.getint(r.styleable.redpacketstyle_speed, 20); minsize = typedarray.getfloat(r.styleable.redpacketstyle_min_size, 0.5f); maxsize = typedarray.getfloat(r.styleable.redpacketstyle_max_size, 1.2f); typedarray.recycle(); init(); } /** * 初始化 */ private void init() { paint = new paint(); paint.setfilterbitmap(true); paint.setdither(true); paint.setantialias(true); animator = valueanimator.offloat(0, 1); setlayertype(view.layer_type_hardware, null); initanimator(); } private void initanimator() { //每次动画更新的时候,更新红包下落的坐标值 animator.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { long nowtime = system.currenttimemillis(); float secs = (float) (nowtime - prevtime) / 1000f; prevtime = nowtime; for (int i = 0; i < redpacketlist.size(); ++i) { redpacket redpacket = redpacketlist.get(i); //更新红包的下落的位置y redpacket.y += (redpacket.speed * secs); //如果y坐标大于view的高度 说明划出屏幕,y重新设置起始位置,以及中奖属性 if (redpacket.y > getheight()) { redpacket.y = 0 - redpacket.height; redpacket.isrealred = redpacket.isrealredpacket(); } //更新红包的旋转的角度 redpacket.rotation = redpacket.rotation + (redpacket.rotationspeed * secs); } invalidate(); } }); //属性动画无限循环 animator.setrepeatcount(valueanimator.infinite); //属性值线性变换 animator.setinterpolator(new linearinterpolator()); animator.setduration(0); } /** *停止动画 */ public void stoprainnow() { //清空红包数据 clear(); //重绘 invalidate(); //动画取消 animator.cancel(); } /** * 开始动画 */ public void startrain() { //清空红包数据 clear(); //添加红包 setredpacketcount(count); prevtime = system.currenttimemillis(); //动画开始 animator.start(); } public void setredpacketcount(int count) { if (mimgids == null || mimgids.length == 0) return; for (int i = 0; i < count; ++i) { //获取红包原始图片 bitmap originalbitmap = bitmapfactory.decoderesource(getresources(), mimgids[0]); //生成红包实体类 redpacket redpacket = new redpacket(getcontext(), originalbitmap, speed,maxsize,minsize,mwidth); //添加进入红包数组 redpacketlist.add(redpacket); } } /** * 暂停红包雨 */ public void pauserain() { animator.cancel(); } /** * 重新开始 */ public void restartrain() { animator.start(); } /** * 清空红包数据,并回收红包中的bitmap */ private void clear() { for (redpacket redpacket :redpacketlist) { redpacket.recycle(); } redpacketlist.clear(); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); //获取自定义view的宽度 mwidth = getmeasuredwidth(); } @override protected void ondraw(final canvas canvas) { //遍历红包数组,绘制红包 for (int i = 0; i < redpacketlist.size(); i++) { redpacket redpacket = redpacketlist.get(i); //将红包旋转redpacket.rotation角度后 移动到(redpacket.x,redpacket.y)进行绘制红包 matrix m = new matrix(); m.settranslate(-redpacket.width / 2, -redpacket.height / 2); m.postrotate(redpacket.rotation); m.posttranslate(redpacket.width / 2 + redpacket.x, redpacket.height / 2 + redpacket.y); //绘制红包 canvas.drawbitmap(redpacket.bitmap, m, paint); } } @override public boolean ontouchevent(motionevent motionevent) { switch (motionevent.getaction()){ case motionevent.action_down: //根据点击的坐标点,判断是否点击在红包的区域 redpacket redpacket = isredpacketclick(motionevent.getx(), motionevent.gety()); if (redpacket != null) { //如果点击在红包上,重新设置起始位置,以及中奖属性 redpacket.y = 0 - redpacket.height; redpacket.isrealred = redpacket.isrealredpacket(); if (onredpacketclicklistener != null) { onredpacketclicklistener.onredpacketclicklistener(redpacket); } } break; case motionevent.action_move: break; case motionevent.action_cancel: case motionevent.action_up: break; } return true; } //根据点击坐标点,遍历红包数组,看是否点击在红包上 private redpacket isredpacketclick(float x, float y) { for (int i = redpacketlist.size() - 1; i >= 0; i --) { if (redpacketlist.get(i).iscontains(x, y)) { return redpacketlist.get(i); } } return null; } public interface onredpacketclicklistener { void onredpacketclicklistener(redpacket redpacket); } private onredpacketclicklistener onredpacketclicklistener; public void setonredpacketclicklistener(onredpacketclicklistener onredpacketclicklistener) { this.onredpacketclicklistener = onredpacketclicklistener; } }
最后
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。