日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android下红包雨的实现

發布時間:2024/1/8 Android 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android下红包雨的实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近做項目的時候,需要做一個類似下紅包雨的效果。經過自己的反復研究,發現使用動畫是最合適的。下面貼出這種實現效果的流程

首先看一下紅包雨的簡單效果圖

  • 首先創建一個用來初始化紅包相關的值的紅包實體類
  • 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;//生成紅包bitmapbitmap = 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;//紅包起始位置yy = -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();}} }
  • 接下來就要需要使用自定義view來實現效果
    (1)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() {@Overridepublic 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);//更新紅包的下落的位置yredPacket.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);}

    (2)view的繪制

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//獲取自定義view的寬度mWidth = getMeasuredWidth();}@Overrideprotected 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);}}

    (3)設置紅包雨的開始結束等事件

    /***停止動畫*/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();}

    (4)設置紅包雨的點擊事件

    @Overridepublic 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;}
  • 在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;@Overrideprotected 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);}@Overridepublic 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() {@Overridepublic void onRedPacketClickListener(RedPacket redPacket) {redRainView1.pauseRain();ab.setCancelable(false);ab.setTitle("紅包提醒");ab.setNegativeButton("繼續搶紅包", new DialogInterface.OnClickListener() {@Overridepublic 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() {@Overridepublic void run() {ab.show();}});}});}/*** 停止下紅包雨*/private void stopRedRain() {totalmoney = 0;//金額清零redRainView1.stopRainNow();}
  • 紅包雨的布局
  • <?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"><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitXY"android:src="@drawable/red_packets_bg" /><Buttonandroid:id="@+id/start"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="開始"/><Buttonandroid:id="@+id/stop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:text="結束"/><TextViewandroid: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.RedPacketTestandroid: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的屬性
  • <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>

    最后貼出紅包雨的完整代碼

    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() {@Overridepublic 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);//更新紅包的下落的位置yredPacket.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();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);//獲取自定義view的寬度mWidth = getMeasuredWidth();}@Overrideprotected 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);}}@Overridepublic 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;} }

    總結

    以上是生活随笔為你收集整理的Android下红包雨的实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。