android 雪花
2017-07-21 16:32:10 qq_35484511 阅读数 162

此文章是参考国外大神做的修改

大神的中文翻译地址:

http://www.open-open.com/lib/view/open1452263908573.html


接下来上效果图:




雪花类我做了修改,定义了九张图片,根据传入的类型绘制不同的雪花

int[] snows = {R.mipmap.snow, R.mipmap.snowmiddle, R.mipmap.snowsmall,
            R.mipmap.snow2big, R.mipmap.snow2middle, R.mipmap.snow2small,
            R.mipmap.snow3big, R.mipmap.snow3middle, R.mipmap.snow3small};

    public Bitmap getBitMap(int type) {
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;//内存可被回收
        opt.inInputShareable = true;
        //获取资源图片
        return BitmapFactory.decodeResource(contexts.getResources(), snows[type]);
    }


在生成雪花时,随机生成不同的类型

protected void resize(int width, int height) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);
        snowflakes = new SnowFlake[NUM_SNOWFLAKES];
        Random random = new Random();
        for (int i = 0; i < NUM_SNOWFLAKES; i++) {
            snowflakes[i] = SnowFlake.create(width, height, paint,random.nextInt(9),context);
        }
    }


在雪花OnDraw方法不停地重绘改变位置

public void draw(Canvas canvas) {
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        move(width, height);
//        canvas.drawCircle(position.x, position.y, flakeSize, paint);
        canvas.drawBitmap(getBitMap(getType()), position.x, position.y, paint);
    }

源码下载:

下载地址点这里

2016-01-25 15:07:28 z240336124 阅读数 4075

1. 效果


这里写图片描述

2.分析和实现


2.1效果分析:

  1. 每个雪花都是随机的一张资源图片(总共五张图片),每一张图片转为bitmap,然后在onDraw中绘制;
  2. 每个雪花它的宽高是随机的范围,旋转的角度是随机的范围,加速度也是随机的;
  3. 每个雪花不拥有一个单独的动画,只用一个动画来控制所有的雪花每一帧的显示;
  4. 每个雪花的运动利用Matrix实现(setTranslate(),postRotate(),postTranslate())

2.2实现单个雪花飘落:

  先实现单个雪花的飘落,新建SingleSnowView extends View , 在他的内部新建一个静态的Snow内部类,Snow类提供一个静态的方法,初始化雪花的大小,旋转角度以及加速度然后返回一个snow实例:

public class SingleSnowView extends View {

    public static class Snow {
        // 旋转角度和速率
        public float rotation;
        public float rotationSpeed;
        // 在view中的x,y点的位置
        public float x, y;
        // 下落的速度
        public float speed;
        // 高度和宽度
        public int width, height;
        // bitmap
        public Bitmap bitmap;

        // 根据宽度存放bitmap,以便同样的宽度可以从集合中获取
        private static HashMap<Integer, Bitmap> bitmapMap = new HashMap<Integer, Bitmap>();

        public static Snow createSnow(Bitmap snowBitmap, int xRange) {
            Snow snow = new Snow();
            // 宽度在8~58之间
            snow.width = (int) (8 + (float) Math.random() * 50);
            // 根据传进来的bitmap宽高求出比例
            float hwRatio = snowBitmap.getHeight() / snowBitmap.getWidth();
            // 算出高度
            snow.height = (int) (snow.width * hwRatio);

            // x位置在[snow.width,所属View中宽度] 任意位置
            snow.x = (float) Math.random() * (xRange - snow.width);

            // 定位雪花垂直稍微偏离的顶部显示
            snow.y = 0 - (snow.height + (float) Math.random() * snow.height);

            // 每秒的下落速度 ( 雪花越大下落得越快) 
            snow.speed = 50 + snow.width * 5;

            // 片开始在-90 - 90度旋转,旋转速度到-45 - 45之间
            snow.rotation = (float) Math.random() * 180 - 90;
            snow.rotationSpeed = (float) Math.random() * 90 - 45;

            // 先根据宽度从缓存中获取
            snow.bitmap = bitmapMap.get(snow.width);
            if (snow.bitmap == null) {
                // 如果缓存中没有,创建,缓存到集合
                snow.bitmap = Bitmap.createScaledBitmap(snowBitmap, snow.width,
                        snow.height, true);
                bitmapMap.put(snow.width, snow.bitmap);
            }
            return snow;
        }

        @Override
        public String toString() {
            return "width:" + width + "  " + "height:" + height + "  "
                    + "speed:" + speed + "  " + "x:" + x + "  " + "y:" + y;
        }
    }
}

每个雪花不拥有单独的动画,只有一个动画用于更新每一帧的动画(更新位置和旋转角度),最后在onDraw()中绘制

public class SingleSnowView extends View {
    // 用于驱动所有单独的片状动画,而不是潜在的数以百计的独立的动画,我们只使用一个,然后更新所有片每一帧的动画。
    private ValueAnimator mAnimator = ValueAnimator.ofFloat(0, 1);
    // 用于追踪时间为动画和 Frames per second
    private long mPrevTime;
    // 单个雪花
    private Snow mSnow;
    private Matrix mMatrix; // 矩阵用于移动每片呈现
    // 雪花显示的bitmap
    private Bitmap mSnowBitmap;

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

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

    public SingleSnowView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initData();
    }

    private void initData() {
        mMatrix = new Matrix();

        mSnowBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.icon_1);

        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator arg0) {
                // 每一帧的动画,我们计算运行时间和更新每一片的位置和旋转它的速度。
                long nowTime = System.currentTimeMillis();
                float secs = (nowTime - mPrevTime) / 1000f;
                mPrevTime = nowTime;
                // 新的位置
                mSnow.y += mSnow.speed * secs;

                if (mSnow.y > getHeight()) {
                    // 如果已经到达底部,从上面从新再来一次,重置snow y 的位置
                    mSnow.y = 0 - mSnow.height;
                }

                // 雪花旋转
                mSnow.rotation = mSnow.rotation + (mSnow.rotationSpeed * secs);

                // 请求重新去刷新绘制界面
                invalidate();
            }
        });
        mAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mAnimator.setDuration(2000);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 利用矩阵去实现
        mMatrix.setTranslate(-mSnow.width / 2, -mSnow.height / 2);
        mMatrix.postRotate(mSnow.rotation);
        mMatrix.postTranslate(mSnow.width / 2 + mSnow.x, mSnow.height
                / 2 + mSnow.y);
        // 绘制雪花
        canvas.drawBitmap(mSnow.bitmap, mMatrix, null);
    }

    /**
     * 开始下雪
     */
    public void startSnow(int rangeWidth) {
        if (mSnow == null) {
            mPrevTime = System.currentTimeMillis();
            mSnow = Snow.createSnow(mSnowBitmap, rangeWidth);
        }
        mAnimator.start();
    }

    /**
     * 停止下雪
     */
    public void stopSnow() {
        // 如果activity进入paused状态 , 也可以调用
        mAnimator.cancel();
    }
}

在Activity中的效果:
这里写图片描述

2.3.满屏雪花飘落

既然一个雪花可以了,那么满屏雪花飘落就很简单了,无非就是将多个雪花放入集合中,在原来的基础上修改一下就可以了:

public class SnowView extends View{
    private Bitmap mSnowBitmapOne, mSnowBitmapTwo, mSnowBitmapThree,
            mSnowBitmapFour, mSnowBitmapFive;
    private ArrayList<Bitmap> mSnowBitmaps;
    // 雪花的个数
    private int mSnowNumber = 0;
    // 最多显示雪花的个数 (75)
    private static final int MAX_SNOW_NUMBER = 75;

    private ArrayList<Snow> mSnows;// 雪花集合


    private void initData() {
        mSnows = new ArrayList<Snow>();

        mSnowBitmapOne = BitmapFactory.decodeResource(getResources(),
                R.drawable.icon_1);
        mSnowBitmapTwo = BitmapFactory.decodeResource(getResources(),
                R.drawable.icon_2);
        mSnowBitmapThree = BitmapFactory.decodeResource(getResources(),
                R.drawable.icon_3);
        mSnowBitmapFour = BitmapFactory.decodeResource(getResources(),
                R.drawable.icon_4);
        mSnowBitmapFive = BitmapFactory.decodeResource(getResources(),
                R.drawable.icon_5);

        mSnowBitmaps = new ArrayList<Bitmap>();
        mSnowBitmaps.add(mSnowBitmapOne);
        mSnowBitmaps.add(mSnowBitmapTwo);
        mSnowBitmaps.add(mSnowBitmapThree);
        mSnowBitmaps.add(mSnowBitmapFour);
        mSnowBitmaps.add(mSnowBitmapFive);

        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator arg0) {
                //....
                for (Snow snow : mSnows) {
                    // ....遍历
                }
                // 请求重新去刷新绘制界面
                invalidate();
            }
        });
    }
}

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (Snow snow : mSnows) {
            // ....遍历
        }
        // TODO 下面计算帧速率
    }

    /**
     * 开始下雪
     */
    public void startSnow(int rangeWidth) {
        mPrevTime = System.currentTimeMillis();
        // 没有添加直接开始下雪时,默认添加15个
        addSnows(15, rangeWidth);
        mAnimator.start();
    }

    public int getSnowNumber() {
        return this.mSnowNumber >= MAX_SNOW_NUMBER ? MAX_SNOW_NUMBER
                : mSnowNumber;
    }

    /**
     * 添加雪花
     */
    public void addSnows(int snowNumber, int rangeWidth) {
        if (mSnowNumber < MAX_SNOW_NUMBER) {
            for (int i = 0; i < snowNumber; i++) {
                // 随机挑选 (也可以根据位置求%,等比例)
                int index = (int) (Math.random() * 5);
                Bitmap snowBitmap = mSnowBitmaps.get(index);
                Snow snow = Snow.createSnow(snowBitmap, rangeWidth);
                // 添加到集合
                mSnows.add(snow);
            }
            // 当前雪花数量叠加
            mSnowNumber += snowNumber;
        }
    }
}

2.4.最后在activity中测试

   public class MainActivity extends Activity {

    private Runnable runnableRain;
    private SnowView snowView;
    @ViewById(R.id.root_view)
    private View mRootView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_first);
        snowView = (SnowView) findViewById(R.id.snow_view);
        ViewUtils.inject(this);
    }

    @OnClick(R.id.tv_play)
    private void startSnow(){
        snowView.setVisibility(View.VISIBLE);
        snowView.startSnow(mRootView.getWidth());

        final Handler handlerRain = new Handler();
        runnableRain = new Runnable() {
            @Override
            public void run() {
                // 每隔两秒添加15个
                snowView.addSnows(15, mRootView.getWidth());
                handlerRain.postDelayed(runnableRain, 2000);
                if(snowView.getSnowNumber() > 75)
                {
                    handlerRain.removeCallbacks(runnableRain);
                }
            }
        };
        handlerRain.postDelayed(runnableRain, 0);
    }
}

快过年了,家里也下雪了,目前只想到了这样一种实现方式,不知道还有没有更好的方式
下载地址:http://download.csdn.net/detail/z240336124/9417303

2015-07-13 14:01:15 ywl5320 阅读数 2143

我的视频课程:《FFmpeg打造Android万能音频播放器》


        由于项目需要实现类似于雪花飘落的效果,在Github中找到了开源项目(NineOldAndroids):https://github.com/JakeWharton/NineOldAndroids/,其中有一个效果就是类似于雪花飘落效果,在这里我只单独把那个效果提取出来了,大家可以下载整个项目自己研究,我们都是站在别人的肩膀上成长的。那咱们先看看效果:


这个效果都是用的android的动画叠加效果实现的,就不多说了,已经写好,有兴趣可以慢慢研究模仿。

这里只提取出啦两个文件,分别是:

1.Flake.java

2.FlakeView.java

由于Demo中是给的一个飘落图片,当然不能很好地展现飘落的多样性,所以我们可以在FlakeView中添加自己的图片(图片最好是正方形的,高度一定要大于等于宽度)。


一、因为每一个图片就是一张Bitmap,所以我们要定义几个Bitmap对象,我这里定义了5个:

    Bitmap droid;       // The bitmap that all flakes use
    Bitmap droid2;
    Bitmap droid3;
    Bitmap droid4;
    Bitmap droid5;


二、然后在构造函数中初始化图片资源:

    droid = BitmapFactory.decodeResource(getResources(), R.drawable.icon_1);
    droid2 = BitmapFactory.decodeResource(getResources(), R.drawable.icon_2);
    droid3 = BitmapFactory.decodeResource(getResources(), R.drawable.icon_3);
    droid4 = BitmapFactory.decodeResource(getResources(), R.drawable.icon_4);
    droid5 = BitmapFactory.decodeResource(getResources(), R.drawable.icon_5);


三、现在我们把图片资源添加到集合中:

修改FlakeView中的addFlakes方法

    public void addFlakes(int quantity) {
	   if(numFlakes <= 75)//这里定义花瓣的数量以及花色样式
	   {
	        for (int i = 0; i < quantity; ++i) {
	        	if(i % 5 == 0)
	        		flakes.add(Flake.createFlake(getWidth(), droid));
	        	else if(i % 5 == 1)
	        		flakes.add(Flake.createFlake(getWidth(), droid2));
	        	else if(i % 5 == 2)
	        		flakes.add(Flake.createFlake(getWidth(), droid3));
	        	else if(i % 5 == 3)
	        		flakes.add(Flake.createFlake(getWidth(), droid4));
	        	else
	        		flakes.add(Flake.createFlake(getWidth(), droid5));
	        }
	        setNumFlakes(numFlakes + quantity);
	   }
    }
因为我的图片为5张,所以这里为了每个图片数量一致,就设定了总数75张(数量多少可以自己设定,可以定义为全局变量,这里就没有定义了),然后循环设置图片到集合里,就有了多种图片了。

要修改的地方基本就是这些了,要修改速度就到Flake中,找到speed中修改即可。

Demo下载地址


2016-08-10 13:32:31 shenggaofei 阅读数 2993


     之前有搜索过相关的信息,但是都不是最全的,下面我们来直接了解这个特效吧:






下面我们来看一看代码的实现吧:


  三个工具类:其中主函数中不需要写代码,只需布局有相应的控件即可,雪花的大小、颜色和数量等可以自己设置


1.***********************************SnowFlake.java*************************************

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;

import me.chunyu.spike.wcl_snowfall_demo.RandomGenerator;

/**
 * 雪花的类, 移动, 移出屏幕会重新设置位置.
 * <p/>
 * Created by wangchenlong on 16/1/24.
 */
public class SnowFlake {
    // 雪花的角度
    private static final float ANGE_RANGE = 0.1f; // 角度范围
    private static final float HALF_ANGLE_RANGE = ANGE_RANGE / 2f; // 一般的角度
    private static final float HALF_PI = (float) Math.PI / 2f; // 半PI
    private static final float ANGLE_SEED = 25f; // 角度随机种子
    private static final float ANGLE_DIVISOR = 10000f; // 角度的分母

    // 雪花的移动速度
    private static final float INCREMENT_LOWER = 2f;
    private static final float INCREMENT_UPPER = 4f;

    // 雪花的大小
    private static final float FLAKE_SIZE_LOWER = 7f;
    private static final float FLAKE_SIZE_UPPER = 20f;

    private final RandomGenerator mRandom; // 随机控制器
    private final Point mPosition; // 雪花位置
    private float mAngle; // 角度
    private final float mIncrement; // 雪花的速度
    private final float mFlakeSize; // 雪花的大小
    private final Paint mPaint; // 画笔

    private SnowFlake(RandomGenerator random, Point position, float angle, float increment, float flakeSize, Paint paint) {
        mRandom = random;
        mPosition = position;
        mIncrement = increment;
        mFlakeSize = flakeSize;
        mPaint = paint;
        mAngle = angle;
    }

    public static SnowFlake create(int width, int height, Paint paint) {
        RandomGenerator random = new RandomGenerator();
        int x = random.getRandom(width);
        int y = random.getRandom(height);
        Point position = new Point(x, y);
        float angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;
        float increment = random.getRandom(INCREMENT_LOWER, INCREMENT_UPPER);
        float flakeSize = random.getRandom(FLAKE_SIZE_LOWER, FLAKE_SIZE_UPPER);
        return new SnowFlake(random, position, angle, increment, flakeSize, paint);
    }

    // 绘制雪花
    public void draw(Canvas canvas) {
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        move(width, height);
        canvas.drawCircle(mPosition.x, mPosition.y, mFlakeSize, mPaint);
    }

    // 移动雪花
    private void move(int width, int height) {
        double x = mPosition.x + (mIncrement * Math.cos(mAngle));
        double y = mPosition.y + (mIncrement * Math.sin(mAngle));

        mAngle += mRandom.getRandom(-ANGLE_SEED, ANGLE_SEED) / ANGLE_DIVISOR; // 随机晃动

        mPosition.set((int) x, (int) y);

        // 移除屏幕, 重新开始
        if (!isInside(width, height)) {
            reset(width);
        }
    }

    // 判断是否在其中
    private boolean isInside(int width, int height) {
        int x = mPosition.x;
        int y = mPosition.y;
        return x >= -mFlakeSize - 1 && x + mFlakeSize <= width && y >= -mFlakeSize - 1 && y - mFlakeSize < height;
    }

    // 重置雪花
    private void reset(int width) {
        mPosition.x = mRandom.getRandom(width);
        mPosition.y = (int) (-mFlakeSize - 1); // 最上面
        mAngle = mRandom.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;
    }
}


2.***********************************SnowView.java*************************************


import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * 雪花视图, DELAY时间重绘, 绘制NUM_SNOWFLAKES个雪花
 * <p/>
 * Created by wangchenlong on 16/1/24.
 */
public class SnowView extends View {

    private static final int NUM_SNOWFLAKES = 150; // 雪花数量
    private static final int DELAY = 5; // 延迟
    private SnowFlake[] mSnowFlakes; // 雪花

    public SnowView(Context context) {
        super(context);
    }

    public SnowView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

   

    @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (w != oldw || h != oldh) {
            initSnow(w, h);
        }
    }

    private void initSnow(int width, int height) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // 抗锯齿
        paint.setColor(Color.WHITE); // 白色雪花
        paint.setStyle(Paint.Style.FILL); // 填充;
        mSnowFlakes = new SnowFlake[NUM_SNOWFLAKES];
        for (int i = 0; i < NUM_SNOWFLAKES; ++i) {
            mSnowFlakes[i] = SnowFlake.create(width, height, paint);
        }
    }

    @Override protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (SnowFlake s : mSnowFlakes) {
            s.draw(canvas);
        }
        // 隔一段时间重绘一次, 动画效果
        getHandler().postDelayed(runnable, DELAY);
    }

    // 重绘线程
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            invalidate();
        }
    };
}


3.*******************************RandomGenerator.java*****************************************


import java.util.Random;

/**
 * 随机生成器
 * <p/>
 * Created by wangchenlong on 16/1/24.
 */
public class RandomGenerator {
    private static final Random RANDOM = new Random();

    // 区间随机
    public float getRandom(float lower, float upper) {
        float min = Math.min(lower, upper);
        float max = Math.max(lower, upper);
        return getRandom(max - min) + min;
    }

    // 上界随机
    public float getRandom(float upper) {
        return RANDOM.nextFloat() * upper;
    }

    // 上界随机
    public int getRandom(int upper) {
        return RANDOM.nextInt(upper);
    }
}


  一个布局:

4.*******************************activity_main.xml*****************************************


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:contentDescription="@null"
            android:scaleType="centerCrop"
            android:src="@drawable/christmas"/>

        <me.chunyu.spike.wcl_snowfall_demo.views.SnowView
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </FrameLayout>

</RelativeLayout>

                                                                                            OK

2016-08-16 18:06:48 rentee 阅读数 358

必须先上图:

这里写图片描述

图片看不到可以上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();

Android 实现雪花飞舞效果

阅读数 316

实现雪花飞舞效果

博文 来自: u013147860

Android实现雪花飘落特效

阅读数 4935

圣诞节各大电商平台app都会有节日的气息,越是优秀的app越会让你感觉到它是一个活生生的app,是有一个强大的运营团队营造的富有生气的app,就像淘宝,圣诞节当天会把app主题更换成圣诞主题一样,图标都换成圣诞节特有的一些物品,而且app界面上也是飘起了雪花,很漂亮,所以在此我也写了一下雪花飘落的demo,不废话了先上图看效果吧。截图效果不咋好,大家可以下载文章末的demo试试。自定义Sno

博文 来自: oMrApollo

android实现漫天雪花&下雨效果

阅读数 1550

**前言:**英文原文地址:https://blog.stylingandroid.com/snowfall/中文翻译地址:http://www.open-open.com/lib/view/open1452263908573.html国外大神实现效果youtube视频地址:https://www.youtube.com/watch?v=pk66ZziTfOw中文翻译是open开发者经

博文 来自: slightfeverGK

Android 实现雪花飘落特效 安卓实现雪花 玫瑰 星星飘落

阅读数 1048

雪花下落的特效,当然代码中实现了 模拟QQ输入特定文字“我想你”时,会下落玫瑰。 这个demo中同时下落【玫瑰】、【星星】、【雪花】。同时下落这个是有3个不同的对象所形成的,当然也可以添加多个形成n个图形的同时下落,都是可以的。然后背景图片是每间隔3s进行自动的变换,(背景图)当然这个变换可以多添加几张图片,自己控制变换的时间间隔都是可以的,自己整理的请各位看官不吝赐

博文 来自: fengshukaihua

android 实现漫天飞舞雪花以及下雨天的效果

阅读数 9491

前言:这个效果实现的原作者是国外一位大神。我在其基础上测试,以及在代码上加了不少注释,以及局部修改。后面我有根据漫天飞舞雪花,实现下雨天场景的效果。原作者项目还是androidstudio版本的。我改成eclipseandroid版本。英文原文地址:https://blog.stylingandroid.com/snowfall/中文翻译地址:http://www.open-op

博文 来自: qq_16064871
没有更多推荐了,返回首页