54、Android 粒子效果之雨(下雨的效果)

核心内容:
1.绘制下雨场景的个体、雨点(直线)
2.让直线动起来
3.处理边界问题
4.构造雨点对象
5.雨点大小设置
6.速度设置和角度设置等
7.添加多个雨点
8.抽离可以在 XML 中影响的属性
9.在代码中解析样式属性并使用其控制雨点变化

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

/**
 * 基类
 */
public abstract class BaseView extends View {
    private MyThread thread;
    private boolean running = true;

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

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

    protected abstract void drawSub(Canvas canvas);
    protected abstract void logic();
    protected abstract void init();
    
    class MyThread extends Thread {
        @Override
        public void run() {
            init();
            while (running) {
                logic();
                postInvalidate();
                try {
                    Thread.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    protected final void onDraw(Canvas canvas) {
        if (thread == null) {
            thread = new MyThread();
            thread.start();
        } else {
            drawSub(canvas);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        running = false;
        super.onDetachedFromWindow();
    }

}

1)简单描述单个雨点的行为。

绘制下雨场景的个体,雨点(直线);

让直线动起来;

处理边界问题;

1 <com.rain.RainView
2         android:layout_width="match_parent"
3         android:layout_height="match_parent"
4         android:background="#ff000000"
5        />
 1   import android.content.Context;
 2 import android.graphics.Canvas;
 3 import android.graphics.Paint;
 4 import android.util.AttributeSet;
 5 
 6 public class RainView extends BaseView {
 8     private float startX;
 9     private float startY;
10     private float stopX;
11     private float stopY;
12     private float sizeX;
13     private float sizeY;
14     private Paint paint;
15 
16     public RainView(Context context, AttributeSet attrs) {
17         super(context, attrs);
19         // 角度。
20         sizeX = 10;
21         sizeY = 30;
22         // 以下是 初始化直线的坐标。
23         startX = 100;
24         startY = 0;
25         // 改变 角度的直线。
26         stopX = startX + sizeX;
27         stopY = startY + sizeY;
28 
29         paint = new Paint();
30         // 把直线 设置成白色。
31         paint.setColor(0xffffffff);
32     }
33 
34     public RainView(Context context) {
35         super(context);
36     }
37 
38     @Override
39     protected void drawSub(Canvas canvas) {
40         // 绘制一条直线
41         canvas.drawLine(startX, startY, stopX, stopY, paint);
42     }
43 
44     @Override   /* 让直线动起来 **/ 
45     protected void logic() {
46 
47         //倍率,通过倍率来改变速度。
48         float opt = 0.5f;
49 
50         startX += sizeX * opt;
51         stopX += sizeX * opt;
52 
53         startY += sizeY * opt;
54         stopY += sizeY * opt;
55 
56         // 当直线走出屏幕的时候,变为初始位置。
57         if (startY > getHeight()) {
58             startX = 100;
59             startY = 0;
60             stopX = startX + 10;
61             stopY = startY + 30;
62         }
63     }
64 
65 }

2)完善雨点行为和构造下雨场景。

构造雨点对象;

雨点大小设置;

速度设置;

角度设置等 添加多个雨点;

1 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
2     android:layout_width="match_parent"
3     android:layout_height="match_parent" >
4     <com.rain.RainView
5         android:layout_width="match_parent"
6         android:layout_height="match_parent"
7         android:background="#ff000000" />
8 </FrameLayout>
 1 public class RainView extends BaseView {
 2     // 多个 “雨点” 对象。
 3     private ArrayList<RainItem> list = new ArrayList<RainItem>();
 4     private int rainNum = 80;  // “雨点”个数。
 5 
 6     public RainView(Context context, AttributeSet attrs) {
 7         super(context, attrs);
 8     }
 9 
10     public RainView(Context context) {
11         super(context);
12     }
13 
14     @Override
15     protected void drawSub(Canvas canvas) {
16         for (RainItem item : list) {
17             item.draw(canvas);
18         }
19     }
20 
21     @Override
22     protected void logic() {
23         for (RainItem item : list) {
24             item.move();
25         }
26     }
27 
28     @Override
29     protected void init() {
30         for (int i = 0; i < rainNum; i++) {
31             RainItem item = new RainItem(getWidth(), getHeight());
32             list.add(item);
33         }
34     }
35 
36 }
 1 /**
 2  * 抽象出一个 雨点 的类
 3  */
 4 public class RainItem {
 5     private int width;
 6     private int height;
 7 
 8     private float startX;
 9     private float startY;
10     private float stopX;
11     private float stopY;
12     private float sizeX;
13     private float sizeY;
14     private float opt;  // 速率
15     private Paint paint;
16     private Random random;  // 随机数
17 
18     // 自定义“雨点”的 宽 和 高
19     public RainItem(int width, int height) {
20         this.width = width;
21         this.height = height;
22         init();
23     }
24 
25     private void init() {
26         random = new Random();
27         // 角度 "X和Y随机。
28         sizeX = 1 + random.nextInt(10);
29         sizeY = 10 + random.nextInt(20);
30         // "雨点"X和Y随机位置。
31         startX = random.nextInt(width);
32         startY = random.nextInt(height);
33         stopX = startX + sizeX;
34         stopY = startY + sizeY;
35         // 速率随机。
36         opt = 0.2f + random.nextFloat();
37         paint = new Paint();
38         
39         paint.setColor(0xffffffff);
40     }
41 
42     public void draw(Canvas canvas) {
43         canvas.drawLine(startX, startY, stopX, stopY, paint);
44     }
45 
46     public void move() {
47         startX += sizeX * opt;
48         stopX += sizeX * opt;
49 
50         startY += sizeY * opt;
51         stopY += sizeY * opt;
52 
53         if (startY > height) {
54             init();
55         }
56     }
57 
58 }

3)在xml中定义可以控制下雨的属性。

抽离可以在xml中影响的属性;

在代码中解析样式属性并使用其控制雨点变化;

res/values/attrs.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <declare-styleable name="RainView">
 4         <!-- 雨点数量 -->
 5         <attr name="rainNum" format="integer"/>
 6         <!-- 雨点大小 -->
 7         <attr name="size" format="integer"/>
 8         <!-- 雨点颜色 -->
 9         <attr name="rainColor" format="integer"/>
10         <!-- 雨点颜色随机 -->
11         <attr name="randColor" format="boolean"/>
12     </declare-styleable>
13 </resources>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:rain="http://schemas.android.com/apk/res/com.jikexueyuan.rain"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <com.rain.RainView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ff000000"
        rain:rainNum="50"
        rain:size="20"
        rain:rainColor="0xff00ff00"
        rain:randColor="true"/>
</FrameLayout>
 1 public class RainView extends BaseView {
 3     // 多个 “雨点” 对象。
 4     private ArrayList<RainItem> list = new ArrayList<RainItem>();
 5     // 以下4个值,均为默认值。
 6     private int rainNum = 80;  // “雨点”个数。
 7     private int size;
 8     private int rainColor;
 9     private boolean randColor;
10 
11     public RainView(Context context, AttributeSet attrs) {
12         super(context, attrs);
13 
14         // 加载,解析 样式属性。res/values/attrs.xml
15         TypedArray ta = context.obtainStyledAttributes(attrs,
16                 R.styleable.RainView);
17 
18         rainNum = ta.getInteger(R.styleable.RainView_rainNum, 80);
19         size = ta.getInteger(R.styleable.RainView_size, 20);
20         rainColor = ta.getInteger(R.styleable.RainView_rainColor, 0xffffffff);
21         randColor = ta.getBoolean(R.styleable.RainView_randColor, false);
22         ta.recycle();
23     }
24 
25     public RainView(Context context) {
26         super(context);
27     }
28 
29     @Override
30     protected void drawSub(Canvas canvas) {
31         for (RainItem item : list) {
32             item.draw(canvas);
33         }
34     }
35 
36     @Override
37     protected void logic() {
38         for (RainItem item : list) {
39             item.move();
40         }
41     }
42 
43     @Override
44     protected void init() {
45         for (int i = 0; i < rainNum; i++) {
46             RainItem item = new RainItem(getWidth(), getHeight(), size,
47                     rainColor, randColor);
48             list.add(item);
49         }
50     }
51 
52 }
 1 /**
 2  * 抽象出一个 雨点 的类
 3  */
 4 public class RainItem {
 5 
 6     private int width;
 7     private int height;
 8 
 9     private float startX;
10     private float startY;
11     private float stopX;
12     private float stopY;
13     private float sizeX;
14     private float sizeY;
15     private float opt;  // 速率
16     private Paint paint;
17     private Random random;  // 随机数
18 
19     private int size = 20;
20     private int color;
21     // 随机 雨点颜色 
22     private boolean randColor = false;;
23 
24     // 自定义“雨点”的 宽 和 高
25     public RainItem(int width, int height) {
26         this.width = width;
27         this.height = height;
28         init();
29     }
30 
31     public RainItem(int width, int height, int size) {
32         this.size = size;
33         this.width = width;
34         this.height = height;
35         init();
36     }
37 
38     public RainItem(int width, int height, int size, int color) {
39         this.color = color;
40         this.size = size;
41         this.width = width;
42         this.height = height;
43         init();
44     }
45 
46     public RainItem(int width, int height, int size, int color,
47             boolean randColor) {
48         this.randColor = randColor;
49         this.color = color;
50         this.size = size;
51         this.width = width;
52         this.height = height;
53         init();
54     }
55 
56     private void init() {
57         random = new Random();
58         // 角度 "X和Y随机。
59         sizeX = 1 + random.nextInt(size / 2);
60         sizeY = 10 + random.nextInt(size);
61         // "雨点"X和Y随机位置。
62         startX = random.nextInt(width);
63         startY = random.nextInt(height);
64         stopX = startX + sizeX;
65         stopY = startY + sizeY;
66         // 速率随机。
67         opt = 0.2f + random.nextFloat();
68         paint = new Paint();
69         if (randColor) {
70             // 颜色随机值。
71             int r = random.nextInt(256);
72             int g = random.nextInt(256);
73             int b = random.nextInt(256);
74 
75             paint.setARGB(255, r, g, b);
76         } else {
77             paint.setColor(color);
78         }
79     }
80 
81     public void draw(Canvas canvas) {
82         canvas.drawLine(startX, startY, stopX, stopY, paint);
83     }
84 
85     public void move() {
86         startX += sizeX * opt;
87         stopX += sizeX * opt;
88 
89         startY += sizeY * opt;
90         stopY += sizeY * opt;
91 
92         if (startY > height) {
93             init();
94         }
95     }
96 
97 }

DEMO下载路径:http://download.csdn.net/detail/androidsj/9279741

原文地址:https://www.cnblogs.com/androidsj/p/4974108.html