過年了,下場紅包雨吧

過年了,下場紅包雨吧

過年了,使用屬性動畫和自定義view作了個下紅包雨的動畫,單機版。java

效果圖:canvas

圖片描述

模擬器鼠標點擊效果不是很好,真機上會好不少.後端

代碼,先自定義一個紅包View,畫出須要的紅包圖片,當紅包被點擊時換一張表示拆開紅包的圖片,其餘的都寫在注視裏.數組

/**
 * Created by weng on 2018/1/27.
 */

public class RedPacketView extends View {

    private float amount;//每一個紅包的金額

    private boolean isClicked;//判斷紅包是否被點擊過,點擊以後再點不會觸發效果

    private Bitmap redPacketBitmap;//紅包對應的bitmap

    private Paint paint;

    private int width = 50;
    private int height= 50;

    public RedPacketView(Context context) {
        this(context, null);
    }

    public RedPacketView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RedPacketView(Context context,  AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //設置默認的爲拆開的紅包圖片
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.red_packet);
        redPacketBitmap = Bitmap.createScaledBitmap(bitmap, (int) dpToPixel(width), (int) dpToPixel(height), false);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //這裏直接設置了大小,若是想更精確一些,也能夠設置爲屏幕寬度和高度的百分比,這樣適配會更好一些
        setMeasuredDimension((int) dpToPixel(width), (int) dpToPixel(height));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(redPacketBitmap, 0, 0, paint);
    }

    //設置紅包被拆開的圖片
    private void setRedPacketBitmap() {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.money);
        redPacketBitmap = Bitmap.createScaledBitmap(bitmap, (int)dpToPixel(width), (int)dpToPixel(height), false);
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();

        switch (action) {
            case MotionEvent.ACTION_DOWN :

                //獲取點擊事件,若是未被拆開,點擊以後設置拆開的圖片
                if (!isClicked()) {
                    setClicked(true);
                    setRedPacketBitmap();
                }

                break;
        }

        return true;
    }

    public float getAmount() {
        return amount;
    }

    public void setAmount(float amount) {
        this.amount = amount;
    }

    public boolean isClicked() {
        return isClicked;
    }

    public void setClicked(boolean clicked) {
        isClicked = clicked;
    }
}

接下來是Activity的設置:dom

public class MainActivity extends AppCompatActivity {

    private int[] mSize;//保存屏幕尺寸
    
    private FrameLayout mFrameLayout;
    
    private int mTotalAmount;//保存搶到的紅包總金額
    
    private int mTotalAccount = 100;//紅包的個數
    
    private int mCurrentAccount;//當前生成的個數,一旦達到總的紅包個數,中止繼續生成紅包

    private static final int mInitY = 60;

    private int mDuration = 3000;//每一個動畫的默認時長
    
    private int mDelay = 300;//每次生成紅包的默認間隔

    private TimeInterpolator[] mInterpolators;//保存不一樣的插值器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSize = getWindowWidthAndHeight(this);//獲取屏幕的寬和高
        initInterpolator();//設置好插值器數組,而後隨機設置插值器,紅包的動畫就會速度不一樣的效果
        mFrameLayout = findViewById(R.id.rl_container);
        
        startAnimation();//開始動畫

    }

    //循環生成紅包,使用static,不持有Activity的引用
    private static Handler mHandler = new Handler();

    private void startAnimation() {

        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {

                if (mCurrentAccount > mTotalAccount) {
                    return;
                }else {
                    mCurrentAccount++;
                }
                
                final RedPacketView redPacketView = new RedPacketView(MainActivity.this);
                redPacketView.setAmount(getRandomFloat(50));//每一個紅包的額度暫定爲50,其實這個應該是後端傳過來的數據,這裏省略
                
                mFrameLayout.addView(redPacketView);//把紅包添加進來
                redPacketView.setX(getInitialX());

                ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(redPacketView, "translationY",
                        -dpToPixel(mInitY),mSize[1] + dpToPixel(mInitY));

                //隨機設置插值器  
                                   objectAnimator.setInterpolator(mInterpolators[getRandomInt(3)]);

                //設置動畫時長,也能夠設置成隨機的
                objectAnimator.setDuration(mDuration);

                //給動畫添加監聽器,當動畫結束時,主要作兩件事1.判斷紅包是否被拆開,如拆開,增長搶到的紅包金額
                //2.remove子view
                objectAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);

                        if (redPacketView.isClicked()) {
                            mTotalAmount += redPacketView.getAmount();

                            Log.e("MainActivity", "搶到的紅包總額  " + mTotalAmount);
                        }

                        mFrameLayout.removeView(redPacketView);//一旦動畫結束,當即remove,讓系統及時回收
                    }
                });

                objectAnimator.start();
                mHandler.postDelayed(this, mDelay);
            }
        }, mDelay);
    }

    //紅包生成時的初始X座標,這裏設置爲0-屏幕width-紅包width
    private float getInitialX(){
        int max = (int)(mSize[0] - dpToPixel(50));
        Random random = new Random();
        float ranNum = random.nextInt(max);
        return ranNum;
    }

    private void initInterpolator () {
        //這裏設置了屬性動畫的不一樣的插值器,第一個是線性Interpolator,勻速,第二個持續加速,第三個先加速再減速
        //若是對動畫還有不瞭解的,推薦博客:http://hencoder.com/page/2/
        mInterpolators = new BaseInterpolator[] {new LinearInterpolator(), new AccelerateInterpolator(),
        new AccelerateDecelerateInterpolator()};
    }

}

最後是工具類Utils:ide

/**
 * Created by why on 2018/1/29.
 */

public class Utils {

    //dp轉px
    public static float dpToPixel(float dp) {
        DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
        return dp * displayMetrics.density;
    }

    //獲取屏幕尺寸
    public static int[] getWindowWidthAndHeight(Context context) {
        WindowManager windowManager = ((Activity)context).getWindowManager();
        return new int[] {windowManager.getDefaultDisplay().getWidth(),
                windowManager.getDefaultDisplay().getHeight() };
    }


    public static float getRandomFloat(int max) {
        Random random = new Random();
        return random.nextInt(max);
    }

    public static int getRandomInt(int max) {
        Random random = new Random();
        return random.nextInt(max);
    }
}

這樣一個簡易的單機版紅包雨就出來了,代碼不多,主要用到的就是動畫的一些知識,若是是要作一個多人拼搶的紅包雨遊戲,還有不少細節優化,包括金額,規則,同步等等。工具

相關文章
相關標籤/搜索