Android雪花下落效果

来源:互联网 发布:美工数字字体图片 编辑:程序博客网 时间:2024/04/30 14:37

必须先上图:

这里写图片描述

图片看不到可以上GitHub看Demo:https://github.com/OptimusPrimeRen/SnowflakesView

再上代码:

(注释还算多,不算太难,就不详述过程了)

public class SnowflakesView extends View {    private FallSnowThread mFallSnowThread;    private Snow[] mSnows; //雪花对象集合    private Drawable mSnowFlowerDrawable;    private int mSnowFlowerHeight; //雪花原始高度    private int mSnowViewWidth; //整个view的高度    private int mSnowViewHeight; //整个view的宽度    private Random mRandom; //随机数发生器,发生雪花缩放大小、雪花初始x轴坐标    private float mFallSpeed; //雪花下降速度    private int mSnowCount; //雪花总数量    private enum FallSnowState {START, PAUSE, RUNNING, STOP}    private FallSnowState mFallSnowState;    public SnowflakesView(Context context) {        this(context, null);    }    public SnowflakesView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public SnowflakesView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initAttrs(context, attrs, defStyleAttr);        initVariable();    }    private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SnowflakesView);        //下落速度        mFallSpeed = typedArray.getFloat(R.styleable.SnowflakesView_fallSpeed, (float) 0.1);        //下落雪花个数        mSnowCount = typedArray.getInteger(R.styleable.SnowflakesView_snowCount, 10);        typedArray.recycle();        judgeAttrIsReasonable();    }    //判断自定义参数是否合法    private void judgeAttrIsReasonable() {        if (mSnowCount <= 0) {            throw new RuntimeException("snow count must > 0");        }        if (mFallSpeed <= 0) {            throw new RuntimeException("fall snow speed must > 0");        }    }    public void initVariable() {        mRandom = new Random();        //此处使用Drawable对象而不是Bitmap,原因是:Drawable提供setAlpha方法,而Bitmap没有。当然,也可以通过设置canvas的alpha,不过测试表示效率较低。        mSnowFlowerDrawable = getResources().getDrawable(R.drawable.image_cpu_cooler_snow);        //获取图片原始高度,用于之后计算        mSnowFlowerHeight = mSnowFlowerDrawable.getIntrinsicHeight();    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);        //整个view的宽高        mSnowViewWidth = r - l;        mSnowViewHeight = b - t;    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (mSnows == null) {            return;        }        for (Snow snow : mSnows) {            canvas.save();            //通过设置Drawable边界,从而Drawable会自动对其中图片进行缩放,注意:这里的四个参数,分别是图片在整个view(canvas)中的顶点            mSnowFlowerDrawable.setBounds((int) snow.mX, (int) snow.mY, (int) (snow.mX + mSnowFlowerHeight * snow.mScale), (int) (snow.mY + mSnowFlowerHeight * snow.mScale));            mSnowFlowerDrawable.setAlpha(snow.mAlpha);            mSnowFlowerDrawable.draw(canvas);            canvas.restore();        }    }    //caculate all snow next attrs , include position,size etc. 计算所有雪花的相关参数  包括位置  大小等    private void calculateSnowsNextAttr() {        for (Snow snow : mSnows) {            snow.calculateNextAttr();        }    }    //单个雪花对象,用于保存雪花的状态    private class Snow {        public float mScale;        public int mAlpha; //alpha        public float mX;        public float mY;        public Snow() {            init();        }        private void init() {            mAlpha = mRandom.nextInt(200) + 55; //55~255 alpha            mScale = (mRandom.nextFloat() + 1) / 2;  //0.5~1.5 scale            mX = mRandom.nextInt(mSnowViewWidth);            mY = -mSnowFlowerHeight;        }        //caculate the snow's next attrs , include position,size etc. 计算下一个雪花的相关参数  包括位置  大小等        public void calculateNextAttr() {            //很简单,当监测到雪花落到view底部时,重新计算初始值。            if (mY > mSnowViewHeight / mScale) {                init();            } else {                //没到底部,以一定速率下降,这里乘以mScale使得越大的落得越快                mY = mY + mScale * mSnowFlowerHeight * mFallSpeed;            }        }    }    //开始下雪    public void startSnow() {        mFallSnowState = FallSnowState.START;        if (mFallSnowThread == null) {            mFallSnowThread = new FallSnowThread();        }        mSnows = new Snow[mSnowCount];        for (int i = 0; i < mSnows.length; i++) {            mSnows[i] = new Snow();        }        if (mFallSnowState == FallSnowState.START) {            mFallSnowThread.start();            mFallSnowState = FallSnowState.RUNNING;        }    }    //暂停下雪    public void pauseSnow() {        if (mFallSnowState == FallSnowState.RUNNING) {            mFallSnowState = FallSnowState.PAUSE;        }    }    //继续下雪    public void resumeSnow() {        if (mFallSnowState == FallSnowState.PAUSE) {            mFallSnowState = FallSnowState.RUNNING;        }    }    //停止下雪    public void stopSnow() {        mFallSnowState = FallSnowState.STOP;    }    private class FallSnowThread extends Thread {        @Override        public void run() {            while (true) {                switch (mFallSnowState) {                    case RUNNING:                        calculateSnowsNextAttr();                        postInvalidate();                        try {                            //大约30帧的动画速度,不会太多冗余计算与刷新                            //当然,如果4.0以上,可以使用valueAnimator,不需新开线程,损耗较小。                            //也可以使用HandlerThread,Timer等,不过本质上都是线程。                            Thread.sleep(30);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        break;                    case PAUSE:                        try {                            Thread.sleep(30);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        break;                    case STOP:                        Thread.interrupted();                        break;                    default:                        break;                }            }        }    }}

使用方法:

1.布局文件

    <com.opr.snowflakesview.SnowflakesView        android:id="@+id/snowflakes"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@android:color/holo_blue_light"        app:fallSpeed="0.1"        app:snowCount="50"/>

2.代码中:

    AppCenterIconView mAppCenterIconView;    mAppCenterIconView = (AppCenterIconView) findViewById(R.id.rl_app_center_icon);    mAppCenterIconView.startAppBoxAnim();
1 0
原创粉丝点击