分析自定義view的實現過程-實現雪花飛舞效果(轉載有改動)

来源:http://www.cnblogs.com/jww-love-study/archive/2016/01/08/5114028.html
-Advertisement-
Play Games

聲明:本文源碼出自實現雪花飛舞效果(有改動)主要通過這篇文來分析自定義view的實現過程。沒事時,比較喜歡上網看看一些新的東西,泡在網上的日子就是一個很不錯的網站。下麵開始了,哈哈。^_^ 大家都知道,自定義view分成三個類型,1、是完全自定義,自己繪製,例如本文講的例子。2、是Groupvie....


聲明:本文源碼出自實現雪花飛舞效果(有改動)主要通過這篇文來分析自定義view的實現過程。

沒事時,比較喜歡上網看看一些新的東西,泡在網上的日子就是一個很不錯的網站。

下麵開始了,哈哈。^_^

  大家都知道,自定義view分成三個類型,1、是完全自定義,自己繪製,例如本文講的例子。2、是Groupview,就是把一些安卓原生提供的控制項組合起來,做成一個有多種功能的組合控制項,如前面寫過的android-oldman之TitleBar.就是這種。3、就是繼承自安卓原來的控制項,然後增加修改成自己需要的功能。如extends TextVeiw後,再裡面做一些更改,text的位置,長度什麼的。相比2,與3,第1種自定義view就是要繼承自view,然後根據需要,測量,繪製。

  最終要的效果是:看到沒有,上面一些彩色的點,就是原來的雪花,當然,你可以通過修改參數,改變雪花數量。

下麵就開始貼代碼了,哈哈哈。

首先,先是定義view

 1 package com.example.jwwsnow;
 2 
 3 import java.util.ArrayList;
 4 import java.util.HashMap;
 5 import java.util.List;
 6 
 7 import android.content.Context;
 8 import android.graphics.Canvas;
 9 import android.graphics.Color;
10 import android.graphics.Paint;
11 import android.util.AttributeSet;
12 import android.util.Log;
13 import android.view.View;
14 
15 public class SnowView extends View {
16     
17     Random random;
18     private static final int NUM_SNOWFLAKES = 15;//雪花數量
19     private static final int DELAY = 1;//畫面延時刷新時間
20 
21     private SnowFlake[] snowflakes;//雪花對像數組。
22 
23     public SnowView(Context context) {
24         super(context);
25     }
26 
27     public SnowView(Context context, AttributeSet attrs) {
28         super(context, attrs);
29     }
30 
31     public SnowView(Context context, AttributeSet attrs, int defStyleAttr) {
32         super(context, attrs, defStyleAttr);
33     }
34 
35     
36     protected void resize(int width, int height) {
37         random = new Random();
38         snowflakes = new SnowFlake[NUM_SNOWFLAKES];
39         for (int i = 0; i < NUM_SNOWFLAKES; i++) {
40             //for迴圈生產雪花。
41             Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
42             paint.setStyle(Paint.Style.FILL);
43             paint.setColor(Color.rgb(random.getColor(), random.getColor(), random.getColor()));
44             //返回的對象存入對象數組中去。
45             snowflakes[i] = SnowFlake.create(width, height, paint);
46             Log.i("SnowDemo", "時間::::::::::"+System.currentTimeMillis());
47         }
48     }
49 
50     /**
51      * View中方法的啟動順序onSizeChanged()>onDraw();
52      */
53     @Override
54     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
55         super.onSizeChanged(w, h, oldw, oldh);
56         if (w != oldw || h != oldh) {
57             resize(w, h);
58         }
59         
60     }
61 
62     @Override
63     protected void onDraw(Canvas canvas) {
64         super.onDraw(canvas);
65         for (SnowFlake snowFlake : snowflakes) {
66             //得到雪花對象,繪製。
67             snowFlake.draw(canvas);
68         }
69         
70         getHandler().postDelayed(runnable, DELAY);//得到子線程,設置5ms延時,每5ms在主線程繪製一次界面。。
71     }
72 
73     private Runnable runnable = new Runnable() {
74         @Override
75         public void run() {
76             invalidate();//此方法會把原來的視圖清除掉,並重新調用veiw.onDraw方法。
77         }
78     };
79 }

可以看到,重寫了view中的幾個方法:

onSizeChanged();
這個方法,是先於onDrow方法執行的。判斷view的size是不是改變,如果改變,則由系統調用。然後才是執行onDrow()方法。
在本例此方法中,系統通過對view的尺寸的判斷,來調用reSize()方法,並把width與heigh傳遞過去。
在reSize()方法中。定義了雪花對象數組SnowFlakes[],通過for迴圈,創建指定數量的雪花對象,併在for迴圈中創建Paint對象,設置畫筆。(ps:Paint與Canvas,paint就像我們平時做畫用的畫筆,我們可以選擇畫筆的顏色,粗細,抗鋸齒,空心,實心,是不是帶陰影等。Canvas,畫布,我們可以用畫布來承載我們要畫的具體事物,如矩形,圓形,線等。要把ptint與canvas區分開,因為功用不同。canvas決定要畫的具體是什麼,print決定用什麼樣的性質去畫嘿嘿,被我說暈沒。)。然後調用下麵要貼的雪花Calss的create方法。這個方法主要是設置一些尺寸,位置等的。然後把這些尺寸位置等參數狀態以對象的形式保存在SnowFalkes[]數組中,供下麵的onDraw方法中去用這些參數做畫。

onDraw()方法中,for迴圈,依次對SnowFalkes[]對象數組中的每個雪花進行繪畫。然後用Handler在主線程中定時重繪一次。
snowFlake.draw(canvas);方法則是具體的進行繪製了。下麵先貼代碼,再接著講。
 1 package com.example.jwwsnow;
 2 
 3 import android.graphics.Canvas;
 4 import android.graphics.Paint;
 5 import android.graphics.Point;
 6 
 7 public class SnowFlake {
 8 
 9     private static final float ANGE_RANGE = 0.1f;    //
10     private static final float HALF_ANGLE_RANGE = ANGE_RANGE / 2f;
11     private static final float HALF_PI = (float) Math.PI / 2f;
12     private static final float ANGLE_SEED = 25f;
13     private static final float ANGLE_DIVISOR = 10000f;
14     private static final float INCREMENT_LOWER = 2f;
15     private static final float INCREMENT_UPPER = 4f;
16     private static final float FLAKE_SIZE_LOWER = 7f;//最小雪花大小
17     private static final float FLAKE_SIZE_UPPER = 20f;//最大雪花大小
18 
19     private final Random random;
20     private final Point position;
21     private float angle;
22     private final float increment;
23     private final float flakeSize;
24     private final Paint paint;
25 
26     public static SnowFlake create(int width, int height, Paint paint) {
27         Random random = new Random();
28         int x = random.getRandom(width);//得到[0~width)的整數width與height都是外層view的尺寸。
29         int y = random.getRandom(height);
30         Point position = new Point(x, y);//設置雪花剛一齣來的隨機位置。
31         //設置Random.getRandom(ANGLE_SEED)/ANGLE_SEED得到[0~1)再*ANGE_RANGE得到[0~0.1f)的數據,再減去0.05得到[-0.05~0.05)的數據。
32         float angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;
33         //得到[2f~4f)的隨機數據
34         float increment = random.getRandom(INCREMENT_LOWER, INCREMENT_UPPER);
35         //得到[7f~20f)的隨機數據
36         float flakeSize = random.getRandom(FLAKE_SIZE_LOWER, FLAKE_SIZE_UPPER);
37         //返回雪花對象。
38         return new SnowFlake(random, position, angle, increment, flakeSize, paint);
39     }
40 
41     SnowFlake(Random random, Point position, float angle, float increment, float flakeSize, Paint paint) {
42         this.random = random;
43         this.position = position;
44         this.angle = angle;//[-0.05~0.05)
45         this.increment = increment;//[2f~4f)
46         this.flakeSize = flakeSize;//[7f~20f)
47         this.paint = paint;
48     }
49 
50     private void move(int width, int height) {
51         //x方向的偏移量小,y方向的大,是為了讓雪花快點落下。
52         double x = position.x + (increment * Math.cos(angle));//Math.cos(angle)約為1
53         double y = position.y + (increment * Math.sin(angle));//Math.sin(0.05~-0.05) = +-[0~8.7)
54       /*
55        *設置雪花的位置為正,不跑出屏幕。[0~1)*2*ANGLE_SEED-ANGLE_SEED等於+-(0~ANGLE_SEED],為+-(0~25f]。然後再/10000f====+-(0~0.0025],
56        *然後再加[-0.05~0.05)泥媽,快算暈了。大神們果然不好理解。(-0.0525~0.0525) 
57        */
58         
59         angle += random.getRandom(-ANGLE_SEED, ANGLE_SEED) / ANGLE_DIVISOR;
60 
61         position.set((int) x, (int) y);//設置新的位置
62 
63         if (!isInside(width, height)) {
64             //如果雪花不在view視圖內,則重設置他們的位置。
65             reset(width);
66         }
67     }
68 
69     private boolean isInside(int width, int height) {
70         //TODO 設置雪花位置
71         int x = position.x;
72         int y = position.y;
73         //判斷x坐標x>雪花尺寸加1距原點的距離(負方向)。x<background寬,同樣的方式理解y。由於上面的設置,其實x方向,雪花是不可能跑出屏幕的,只有y方向上會。
74         return x >= -flakeSize - 1 && x + flakeSize <= width && y >= -flakeSize - 1 && y - flakeSize < height;
75         
76     }
77 
78     private void reset(int width) {
79         //當雪花落到屏幕最下方以下時,重新設置雪花從
80         position.x = random.getRandom(width);//x軸設設置一個view內的隨機位置就行
81         position.y = (int) (-flakeSize - 1);//view的(0,0)點在view的左上角,所以,當y為負時,則在view的上方。看起來像是一個新的雪花從上落下。
82         angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;
83     }
84 
85     public void draw(Canvas canvas) {
86         //繪製方法 
87         int width = canvas.getWidth();
88         int height = canvas.getHeight();//雪花所整個view高度與寬度
89         move(width, height);//雪花移動,傳的參數為view的的北景大小。
90       //畫一個個雪花。其實就是畫一個個球。其坐標,尺寸,畫筆都是原來在create方法時就定義 了的,之後保存在flakesnow數組裡了。
91         canvas.drawCircle(position.x, position.y, flakeSize, paint);
92     }
93 
94 
95 }

  先跳到前面的onSizeChange()方法來說。可以看到,當調用SnowFlake.create()方法後,最後返回的是:(裡面的Random對象也是重新進行封裝的,馬上貼上)

1 return new SnowFlake(random, position, angle, increment, flakeSize, paint);

  這個是用來繪製SnowFlake時需要的參數。然後在onSizeChange()方法調用的reSize()方法中保存進入了雪花數組SnowFlakes[i]。

 

再跳到上面大段代碼前面的接著說,在onDraw()方法中,for迴圈會依次繪製每個雪花。snowFalke.draw().就是snowflakes[i] = SnowFlake snowFlake();

snowFlake再調用自己的draw()方法。由於前面每個SnowFlake對象都保存了每個雪花的參數,所以在draw()中,用的就直接使用了。

雪花是要下落的,則在draw()方法中,調用move()方法,來設置每個雪花的位置。當雪花位置跑出屏幕後再調用reset()方法,重新設置雪花從屏幕最上方重新落下。

下麵是代碼中用來設置隨機數據的Random對象封裝。

 1 package com.example.jwwsnow;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 public class Random {
 7 
 8      private static final java.util.Random RANDOM = new java.util.Random();
 9 
10         public float getRandom(float lower, float upper) {
11             float min = Math.min(lower, upper);//返回兩者較小的一個。
12             float max = Math.max(lower, upper);
13             return getRandom(max - min) + min;//返回的是比最大的小,比最小的大的數。
14         }
15 
16         public float getRandom(float upper) {
17             return RANDOM.nextFloat() * upper;//Random.nextFloat()生成[0~1)的數.
18         }
19 
20         public int getRandom(int upper) {
21             return RANDOM.nextInt(upper);//隨機生成比[0~upper)的數值。
22         }
23         public int getColor(){
24             return RANDOM.nextInt(255);//隨機生成[0~255)整數。
25             
26         }
27 }

然後就是使用了:xml引用,要把路徑寫完整。

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3   xmlns:tools="http://schemas.android.com/tools"
 4   android:layout_width="match_parent"
 5   android:layout_height="match_parent"
 6   tools:context="com.stylingandroid.snowfall.MainActivity">
 7 
 8   <ImageView
 9     android:id="@+id/image"
10     android:layout_width="match_parent"
11     android:layout_height="match_parent"
12     android:layout_centerInParent="true"
13     android:contentDescription="@null"
14     android:scaleType="fitCenter"
15     android:src="@drawable/tree" />
16 
17   <com.example.jwwsnow.SnowView
18     android:layout_width="match_parent"
19     android:layout_height="match_parent"
20     android:layout_alignBottom="@id/image"
21     android:layout_alignEnd="@id/image"
22     android:layout_alignLeft="@id/image"
23     android:layout_alignRight="@id/image"
24     android:layout_alignStart="@id/image"
25     android:layout_alignTop="@id/image" />
26 </RelativeLayout

本文主要用來複習自定義view的流程。建議先看原文。^_^

下麵把我註釋改變後的一些代碼發上來,僅做研究用(eclipse版的。。。)。

ca,博客園不能上傳代碼。等我上傳到git上或360雲盤。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 讓你像使用普通按鈕一樣,只用設置倒計時時長就可以實現倒計時功能
  • 準備數據 首先先加入一些資源文件:先建立一個xcassets文件,放入圖片:再建立一個plist文件,寫入與圖片對應的內容:在ViewController中讀取plist到詞典中:
  • ToggleButton(開關按鈕)和Switch(開關)講解:一、核心屬性講解:(1)ToggleButtontextOn:按鈕被選中的時候文字顯示textOff:按鈕沒有被選中的時候文字顯示(2)switch:showText:設置textOn/off的時候文字是否顯示android:showT...
  • 初學android,捧著一本書,第一個接觸的就是adb,在android路上...
  • tag是UIView的一個屬性,而且要求tag值唯一。父視圖可以通過tag來找到一個子視圖1 UIView *redView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.window.frame), ...
  • RadioButton(單選框)和CheckBox(覆選框)講解:一、基本用法和事件處理(1)RadioButton單選框,就是只能選擇其中的一個,我們在使用的時候需要將RadioButton放到RadioGroup中使用,同時我們還可以在RadioGroup中設置 orientation屬性來控制...
  • 一.先來研究下這個軟體-》Appicon and Launchimage Maker首先打開你電腦上的AppStore,然後搜索:AppIcon然後回車:這裡我們先使用免費版的點擊下載。(左上角那個)然後打開軟體,應該是這樣的:軟體好人性化,給我們標註了1,2,3該幹啥。1選圖片唄。2.選是要給什麼...
  • 在平時的工作中,會經常用到adb命令,在這裡稍微整理了一下。一.概要1.什麼是adb?adb全稱為Android Debug Bridge,就是起到調試橋的作用。顧名思義,adb就是一個debug工具。2.adb工作原理不是很理解?那就來看看它的工作原理吧。上圖是一個簡單的adb工作原理圖。adb客...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...