2017了,回家前 "年末" 分享:下雨,飄雪,紅包雨,碰撞球,自定義View


(本博客為原創:http://www.cnblogs.com/linguanh/)

 

目錄:

  效果展示

  感想

  代碼拆解

  開源地址

 

效果展示

  有沒有興趣繼續看下去,直接看下"顏值"是第一步了。依次對應:下雨,飄雪,紅包雨,碰撞球

   

  上面是圖片,這里再發個視頻鏈接:http://pan.baidu.com/s/1miyPn76

感想

  16年總算過去了,跟各位猿友有說句祝福吧,新的一年少加點班,身體健康,錢能賺多少就盡量賺。

  之前看博客園,很多發純感想的,都被推薦了好幾天,說實話,我幾乎一拉到底,就看有沒有點↓的。

  公司放假時間是在23號,也就明天了,大四實習到現在,一直很忙,這段時間也是我在編程層面上學到了比較多東西的階段,上面的自定義View是Android的,完成它們是在實習上班期間擠出時間做的,最初的初衷是想把第四個碰撞球的效果加入到畢設里面,現在總算是實現了,過程遇到很多問題,球體的碰撞處理比想象中麻煩很多,前三個比較簡單,也是微信,QQ的下表情原理吧,我猜應該是。。。

  畢設最終也會開源,還請大家留意我 GitHbub,這將會是一個集合非第三方IM和仿朋友圈+golang制作服務端等等知識的社交APP。

 

代碼拆解

  如果你仔細看了上面的四張效果圖,你會發現,前三張是沒碰撞效果處理的,而第四張是具備的。這也是我要區分實現的效果,目的是為了表明,不僅可以不碰撞還可以選擇碰。

  同時,飄雪和紅包雨,事實也僅僅是圖片的不同,這就對了。你只需要修改圖片就能實現完全自定義,愛下什么下什么。

  言歸正傳,整體使用了 適配器設計模式。代碼是很簡練易懂的,可以看看我的目錄結構。

  

  基類是一個暴露繪制和邏輯抽象方法的View子類,所有自定義View需要繼承它。子類只需要關注自己要繪制什么,以及我要繪制的東西怎么去不斷地改變,邏輯改變設計在一個 Thread 線程里面,采用 postInvalidate 通知 UI 刷新。

 1 /**
 2  * Created by LinGuanHong on 2017/1/15.
 3  *
 4  * My GitHub : https://github.com/af913337456/
 5  *
 6  * My Blog   : http://www.cnblogs.com/linguanh/
 7  *
 8  */
 9 
10 public abstract class BaseView extends View {
11 
12     protected String TAG = "zzzzz";
13     private static final int sleepTime = 30;
14     private RefreshThread refreshThread = null;
15 
16     public BaseView(Context context) {
17         super(context);
18     }
19 
20     public BaseView(Context context, AttributeSet attrs) {
21         super(context, attrs);
22     }
23 
24     public abstract void drawSub(Canvas canvas);
25 
26     public abstract void baseInit(int width,int height);
27 
28     public abstract void logic();
29 
30     @Override
31     protected final void onDraw(Canvas canvas) {
32         if(refreshThread == null){
33             refreshThread = new RefreshThread();
34             refreshThread.start();
35         }else{
36             drawSub(canvas);
37         }
38     }
39 
40     @Override
41     protected void onDetachedFromWindow() {
42         running = false;
43         super.onDetachedFromWindow();
44     }
45 
46     private boolean running = true;
47     private class RefreshThread extends Thread{
48 
49         @Override
50         public void run() {
51             baseInit(getWidth(),getHeight());
52             while (running){
53                 try{
54                     logic();
55                     postInvalidate();
56                     Thread.sleep(sleepTime);
57                 }catch (Exception e){
58                     Log.d(TAG,e.toString());
59                 }
60             }
61         }
62     }
63 }
View Code

   BaseView 已經是一個可以直接繼承的父類了,如果僅僅只是繪制一些比較簡單邏輯的自定義View,繼承它足以,但是要實現上述的效果,還需要添加多一個抽象類,無論是雨景還是雪景,它們都是個體的集合,也就是說,我們需要一個"景"的抽象。

  ShowView 是一個具備泛型的抽象類,它是景色的制作者,至於是什么景,由你來決定,也就是泛型的傳入。例如,我要制造雨景,那么我就傳入雨點,雪景就是雪塊

 

 1 /**
 2  * Created by LinGuanHong on 2017/1/15.
 3  *
 4  * My GitHub : https://github.com/af913337456/
 5  *
 6  * My Blog   : http://www.cnblogs.com/linguanh/
 7  *
 8  */
 9 
10 public abstract class ShowView<T extends BaseItem> extends BaseView {
11 
12     protected List<T> itemList = new ArrayList<>();
13     protected int size = 1;
14 
15     public ShowView(Context context) {
16         super(context);
17     }
18 
19     /** 子類實現布局必須要重寫這個構造方法 */
20     public ShowView(Context context, AttributeSet attrs) {
21         super(context, attrs);
22     }
23 
24     @Override
25     public void drawSub(Canvas canvas) {
26         for(T t:itemList){
27             t.draw(canvas);
28         }
29     }
30 
31     @Override
32     public void logic() {
33         beforeLogicLoop();
34         for(T t:itemList){
35             t.move();
36         }
37     }
38 
39     public abstract void beforeLogicLoop();
40     public abstract T getItem(int width, int height,Resources resources);
41     public abstract int getCount();
42 
43     @Override
44     public void baseInit(int width, int height) {
45         size = getCount();
46         Resources resources = getResources();
47         for(int i = 0; i< size; i++){
48             itemList.add(getItem(width,height,resources));
49         }
50     }
51 
52 }
View Code

  由於我們的景色里面的個體可能是各種各樣,那么為了使他們都能具備一些公共的屬性,需要再抽象一個基礎的個體類,共不同的景色個體繼承。

 1 /**
 2  * Created by LinGuanHong on 2017/1/15.
 3  *
 4  * My GitHub : https://github.com/af913337456/
 5  *
 6  * My Blog   : http://www.cnblogs.com/linguanh/
 7  *
 8  * 公共的屬性和行為
 9  *
10  */
11 
12 public abstract class BaseItem {
13 
14     protected int width,height;      /** 景內寬高 */
15     protected Resources resources;
16 
17     public BaseItem(int width,int height,Resources resources){
18         this.width  = width;
19         this.height = height;
20         this.resources = resources;
21     }
22 
23     public abstract void draw(Canvas canvas); /** 顯示 */
24     public abstract void move();     /** 運動 */
25 
26 }

  OK,到這里基礎的類都搞定了,為什么說是適配器模式呢,其實 BaseItem 就是 ViewHolder,ShowView 是 BaseAdapter,下面放下雨的Item 類和雨景。

  注意注釋,代碼很簡練易懂!

 1 /**
 2  * Created by LinGuanHong on 2017/1/15.
 3  *
 4  * 造雨,造多少個,160個,具體是什么雨,交給 item 實現
 5  *
 6  */
 7 
 8 public class RainView extends ShowView<RainItem> {
 9 
10 
11     public RainView(Context context) {
12         super(context);
13     }
14 
15     public RainView(Context context, AttributeSet attrs) {
16         super(context, attrs);
17     }
18 
19     @Override
20     public void beforeLogicLoop() {
21 
22     }
23 
24     @Override
25     public RainItem getItem(int width, int height, Resources resources) {
26         return new RainItem(width,height,resources); /** 要造的雨,是什么雨就在這里傳入 */
27     }
28 
29     @Override
30     public int getCount() { /** 要制作的雨數目 */
31         return 160;
32     }
33 }

  我要制作的雨,隨機數可以自定義。

 1 /**
 2  * Created by LinGuanHong on 2017/1/15.
 3  */
 4 
 5 public class RainItem extends BaseItem {
 6 
 7     private float opt;
 8     private int sizeX,sizeY; /** 充當角度 */
 9     private int startX,startY,stopX,stopY;
10     private Paint paint;
11     private Random random;
12 
13     public RainItem(int width, int height, Resources resources) {
14         super(width,height,resources);
15         init();
16         loopInit();
17     }
18 
19     @Override
20     public void move() {
21         startX += sizeX * opt;
22         stopX  += sizeX * opt;
23 
24         startY += sizeY * opt;
25         stopY  += sizeY * opt;
26         if(startY > height){
27             loopInit();
28         }
29     }
30 
31     @Override
32     public void draw(Canvas canvas) {
33         Log.d("zzzzz","drawView "+startX+" "+startY+" "+stopX+" "+stopY);
34         canvas.drawLine(startX,startY,stopX,stopY,paint);
35     }
36 
37     private void loopInit(){
38         sizeX = 1  + random.nextInt(10);
39         sizeY = 10 + random.nextInt(20);
40 
41         startX = random.nextInt(width );
42         startY = random.nextInt(height);
43 
44         opt = 0.2f + random.nextFloat();
45 
46         stopX = startX + sizeX;
47         stopY = startY + sizeY;
48     }
49 
50     private void init(){
51         paint = new Paint(Paint.ANTI_ALIAS_FLAG); /** 抗鋸齒  */
52         paint.setColor(0xffffffff); /** a,r,g,b 255,255,255,255 */
53 
54         random = new Random();
55     }
56 
57 }

   到這里總結一下,如果你想實現自己的自定義View,不妨直接繼承 BaseView,然后寫你自己的 Item,就可以了。

開源地址

  我的:https://github.com/af913337456/XView

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM