1. 單個雨點的行為
2. 完善雨點的行為和構造下雨場景
3. 在XML中定義可以控制下雨的屬性
------------------------------------------------------
1. 單個雨點的行為: 一條線段在運動
起始點:startX , startY;
終止點:stopX, stopY;
自定義View的框架類
public abstract class BaseView extends View { Thread thread; public BaseView(Context context, AttributeSet attrs) { super(context, attrs); } public BaseView(Context context) { super(context); } @Override final protected void onDraw(Canvas canvas) { //禁止子類覆蓋,用final if(thread == null ) { thread = new MyThread(); thread.start(); } else{ drawSub(canvas); } } protected abstract void logic(); protected abstract void drawSub(Canvas canvas); @Override final protected void onDetachedFromWindow() { // 離開屏幕時結束 //onDetachedFromWindow在銷毀資源(既銷毀view)之后調用 running = false; super.onDetachedFromWindow(); } private boolean running = true; class MyThread extends Thread { @Override public void run() { while(running) { logic(); postInvalidate(); //線程中更新繪制,重新調用onDraw方法 try { Thread.sleep(50); //速度太快肉眼看不到,要睡眠 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
自定義單個雨點RainView
public class RainView extends BaseView { private float startX = 0; private float startY = 0; // Start Point private float stopX = 0; private float stopY = 0; // Stop Point private float sizeX = 0; private float sizeY = 0; private Paint paint; public RainView(Context context) { super(context); // TODO Auto-generated constructor stub } public RainView(Context context, AttributeSet attrs) { super(context, attrs); sizeX = 10; sizeY = 30; //單個雨點的形狀,用線段表示 startX = 100; startY = 0; stopX = startX + sizeX; stopY = startY + sizeY; paint = new Paint(); paint.setColor(0xffffffff); } @Override protected void logic() { // 讓雨點運動 float opt = 0.3f; startX += sizeX * opt; stopX += sizeX * opt; startY += sizeY * opt; stopY += sizeY * opt; // 雨點出了屏幕的時候讓它回到起始點 if(startY > getHeight() || startX > getWidth()){ startX = 100; startY = 0; stopX = startX + sizeX; stopY = startY + sizeY; } } @Override protected void drawSub(Canvas canvas) { // drawSub 完成繪制操作 canvas.drawLine(startX, startY, stopX, stopY, paint); } }
在布局文件中使用
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.carloz.raineffect.MainActivity" > <com.carloz.raineffect.v1.single_rain.RainView android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff000000" /> </FrameLayout>
效果如下:
2. 完善雨點的行為和構造下雨場景
2.1 將雨點 效果和 行為 抽象出來
* 雨點的速度和長度是可變的
* 雨點的傾斜角度是可變的
* 雨點的位置是可變的
public class RainItem { private int width; private int height; public RainItem(int width, int height) { this.width = width; this.height = height; init(); } private float startX = 0; private float startY = 0; // Start Point private float stopX = 0; private float stopY = 0; // Stop Point private float sizeX = 0; private float sizeY = 0; private Paint paint; private float opt; private Random random; public void init() { // TODO Auto-generated method stub random = new Random(); sizeX = 1 + random.nextInt(10); // 隨機改變雨點的角度 sizeY = 1 + random.nextInt(20); // 單個雨點的形狀,用線段表示 startX = random.nextInt(this.width); startY = random.nextInt(this.height); // 隨機改變雨點的位置 stopX = startX + sizeX; stopY = startY + sizeY; paint = new Paint(); paint.setColor(0xffffffff); } public void draw(Canvas canvas) { canvas.drawLine(startX, startY, stopX, stopY, paint); } public void move() { // 讓雨點運動 opt = 0.2f + random.nextFloat(); // 隨機改變雨點的速度和長度 startX += sizeX * opt; stopX += sizeX * opt; startY += sizeY * opt; stopY += sizeY * opt; // 雨點出了屏幕的時候讓它回到起始點 if (startY > this.height || startX > this.width) { startX = random.nextInt(this.width); startY = random.nextInt(this.height); stopX = startX + sizeX; stopY = startY + sizeY; } } }
2.2 定義多個雨點
在 添加抽象 BaseView 方法: protected abstract void init();
class MyThread extends Thread { @Override public void run() { init(); while(running) { logic(); postInvalidate(); //線程中更新繪制,重新調用onDraw方法 try { Thread.sleep(50); //速度太快肉眼看不到,要睡眠 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
public class RainView extends BaseView { ArrayList<RainItem> rainList = new ArrayList<RainItem>(); int size = 80; public RainView(Context context) { super(context); } public RainView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void init() { // TODO Auto-generated method stub for (int i = 0; i < size; i++) { RainItem item = new RainItem(getWidth(), getHeight()); rainList.add(item); } } @Override protected void logic() { for (RainItem item : rainList) { item.move(); } } @Override protected void drawSub(Canvas canvas) { // drawSub 完成繪制操作 for (RainItem item : rainList) { item.draw(canvas); } } }
效果如下:
3. 在XML中定義可以控制下雨的屬性