Android实现红包雨动画效果

Android实现红包雨动画效果,第1张

概述本文介绍了Android实现红包雨动画效果,分享给大家,希望对大家有帮助红包雨

本文介绍了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,R.styleable.RedPacketStyle);    count = typedArray.getInt(R.styleable.RedPacketStyle_count,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(),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,paint);    }  }  @OverrIDe  public boolean ontouchEvent(MotionEvent motionEvent) {    switch (motionEvent.getAction()){      case MotionEvent.ACTION_DOWN:        //根据点击的坐标点,判断是否点击在红包的区域        RedPacket redPacket = isRedPacketClick(motionEvent.getX(),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;  }}

最后

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

总结

以上是内存溢出为你收集整理的Android实现红包雨动画效果全部内容,希望文章能够帮你解决Android实现红包雨动画效果所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1145581.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存