本文介绍了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"?>    

自定义view的styleable

                    

完整的自定义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 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;  }}

最后

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

更多相关文章

  1. Android(安卓)Launcher3 禁止用户拖动图标创建文件夹,控制拖动图
  2. [Android(安卓)Pro] ListView,GridView之LayoutAnimation特殊动
  3. ViewPager如下效果你研究过吗?
  4. Android组件Activity中的View绘画和动画(Animation)是否会重画?
  5. Android(安卓)首个Activity启动动画设置
  6. Android中组件的动画效果之平移动画
  7. 为Activity之间跳转添加动画
  8. 如何避免打开键盘或横竖屏切换,active重启,处理界面的延迟动画
  9. Android箭头图标移动动画实现

随机推荐

  1. Android 存储设备管理 -- IMountService (二
  2. android按Menu出现菜单的动画
  3. 刚学android,练手写的一个播放器
  4. Android 给GridView添加分割线
  5. android sd 卡操作
  6. Android9.0 修改状态栏图标之间的间距
  7. android 获取设备Id等信息
  8. Android简单实现启动画面的方法
  9. 运行Android(安卓)studio报错com.google.
  10. Android Studio安装以及解决连不上Androi