核心内容:
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