电竞比分网-中国电竞赛事及体育赛事平台

分享

android中

 點(diǎn)點(diǎn)滴滴 2012-09-14

android中-自定義View對象

已有 430 次閱讀2011-8-24 23:10 |個人分類:android 學(xué)習(xí)篇

我們知道android SDK中的UI控件都是View或ViewGroup的子類(ViewGroup也是View的子類),我們將View細(xì)分為單獨(dú)View和容器View 兩種,所以就衍生兩個視圖基類:View和ViewGroup。通過擴(kuò)展這兩個基類,Android SDK提供了一系列功能強(qiáng)大,設(shè)計(jì)巧妙的UI控件,但是用戶的需求是千變?nèi)f化的,SDK中不可能提供所有可能用到的UI形式,所以這就需要允許用戶自定義 View對象來完成他們所需要的效果。

幸好,Android SDK有支持自定義View對象,它允許你自定義一個類,繼承android.view.View對象,然后你只需要調(diào)整它里面的一些方法即可,那到底要 重寫哪些方法呢?如果你對android.view.View本身都不是很熟悉的話,那怎么會自定義view呢,就像是還不會走路,怎么就想學(xué)跑步了,所 以我們首先要先了解一些關(guān)于View的東西。

了解android.view.View

我們在了解Activity時(shí)就有提到,只要有能看到的UI界面,就一定有Activity。這邊所說的UI界面就是指View對象,所以View 和Activity離不開關(guān)系。當(dāng)Activity處于Active狀態(tài)時(shí)(Activity獲取了當(dāng)前的焦點(diǎn)),它就發(fā)出請求要求繪制Activity 中的View對象。系統(tǒng)根據(jù)視圖的關(guān)系層次從根節(jié)點(diǎn)出發(fā)開始繪制直到所有的葉子節(jié)點(diǎn)(因?yàn)?a title="Android應(yīng)用程序原理" href="http://www./index.php/tutorial/android-to-new/principles-of-android-applications.html" target="_blank">View是有層次關(guān)系的), 整個繪制過程中View和ViewGroup的實(shí)現(xiàn)形式是不一樣的,因?yàn)閂iewGroup里面會有子視圖對象,所以它需要請求子視圖執(zhí)行繪制,整個視圖 樹執(zhí)行繪圖的順序是中序遍歷,從根節(jié)點(diǎn)先畫,最后才是子節(jié)點(diǎn)。如果是View那么只要確定了它的大小即可執(zhí)行繪制方法。

繪制ViewGroup時(shí)可以分為兩個步驟:measure測量過程和layout布局過程。measure是用來測量ViewGroup所占用的 尺寸,它按照中序遍歷的方式遞歸調(diào)用子視圖的measure方法,然后保存各個子視圖對應(yīng)測量出來的結(jié)果。當(dāng)measure測量完成后就會調(diào)用 layout過程,layout過程也是使用中序遍歷遞歸調(diào)用,它做的工作是確定每個父視圖的尺寸,因?yàn)樵趍easure階段已經(jīng)完成了所有的子視圖尺 寸,所以父視圖的尺寸也可以通過它計(jì)算出來。

當(dāng)measure測量執(zhí)行完成后,你就已經(jīng)知道每個視圖所需的尺寸了,所以你需要設(shè)置值,讓getMeasureWidth和 getMeasureHeight方法可以獲取測量得到的結(jié)果。measure測量的結(jié)果必須考慮父視圖設(shè)置的長度,確保測量完成后得到的結(jié)果滿足:所有 的父視圖的尺寸都能裝得下它們各自的所有子視圖。一個父視圖可能會多次調(diào)用它的子視圖的measure方法,因?yàn)橐晥D可以設(shè)置成最大尺寸 (fill_parent),它首先會不限制子視圖的大小,讓子視圖能盡量大,但是如果有兩個子視圖都采用最大尺寸(fill_parent),那么只能 采取折中方式。

measure測量過程用兩個類來協(xié)助確定尺寸:MeasureSpec和LayoutParams。MeasureSpec用來對父視圖描述它需要的尺寸或位置,LayoutParams用來描述它需要的寬度和高度,它可定義的尺寸分為3種模型:

  1. 確定值:直接確定它的大小
  2. FILL_PARENT:填充父視圖的空間(最大占用空間)
  3. WRAP_CONTENT:能剛好顯示出視圖內(nèi)容的大小區(qū)域即可(最小占用空間)

MeasureSpec用來讓父視圖通知子視圖,子視圖所能分配的大小,它分為下面3種模型:

  1. UNSPECIFIED:讓父視圖直接按照子視圖需求的尺寸進(jìn)行分配,比如一個LinearLayout在measure中就對子視圖使用UNSPECIFIED模型,它不限制大小,按照子視圖的需求進(jìn)行分配。
  2. EXACTLY:強(qiáng)迫子視圖的尺寸必須按照父視圖分配的尺寸進(jìn)行測量,如果子視圖的實(shí)際尺寸比這個尺寸大則需要縮小,如果子視圖的實(shí)際尺寸比這個尺寸小則需要擴(kuò)大。
  3. AT_MOST:強(qiáng)迫讓子視圖使用最大的尺寸,子視圖的尺寸不得大于父視圖定義的最大尺寸,但是可以小于這個最大尺寸值(跟EXACTLY不一樣的是它可以小于這個尺寸值)。

 

創(chuàng)建自定義View對象

了解了View測量和繪制的原理后,你就可以通過繼承它,重寫特定的方法創(chuàng)建一個自定義View對象。一般創(chuàng)建自定義View的用途是:

1.  自定義視圖對象,創(chuàng)建一個SDK沒提供的布局形式,如Accordion。

2. 將多個View對象組合起來封裝成一個新的自定義View對象,如Combox就是由一個下拉列表和一個輸入框和輸入框右邊一個按鈕組成的。

3. 改寫EditText對象,Android SDK中的記事本例子就使用了擴(kuò)展EditText的視圖,它在每行文字的下面畫一條藍(lán)色的線。

4. 創(chuàng)建一個游戲面板,捕捉一些鍵盤或觸摸事件做出一些特定的處理。

 

如何創(chuàng)建自定義View對象

主要有下面幾個步驟:

1. 創(chuàng)建一個自定義類,繼承android.view.View。

2. 重寫父類構(gòu)造方法,你可以在構(gòu)造方法中獲取在xml布局文件里設(shè)置的屬性,你可以從這里讀取一些自定義的屬性配置View對象。

3. 重寫父類(View)的方法,這邊可以根據(jù)需要修改的程度有選擇的重寫,這些重寫的方法都是on開頭的方法如:onDraw、onMeasure或 onKeyDown(這些跟Activity生命周期中的onCreate,onPause…一樣也算繪制過程的生命周期)。如果你沒有重寫onDraw 默認(rèn)它不做任何事,所以你會看到一片空白區(qū)域,onMeasure默認(rèn)會創(chuàng)建一個100 * 100的區(qū)域

4.  使用這個對象

一般我們?nèi)绻麤]有在xml布局文件中使用一些自定義的配置屬性可以不用重寫構(gòu)造方法,這時(shí)候我們只需要重寫onMeasure和onDraw方法。 onMeasure方法被調(diào)用時(shí)有兩個參數(shù):widthMeasureSpec和heightMeasureSpec這個參數(shù)是int型,用來表示寬度和 高度的尺寸,在onMeasure中必須根據(jù)這兩個參數(shù)確定View的寬度和高度值,然后調(diào)用setMeasureDimension(int width,int height)方法設(shè)置視圖的顯示區(qū)域范圍,否則將會拋出異常。在onDraw方法中,會有一個調(diào)用參數(shù):Canvas,你可以使用它進(jìn)行繪制View的 操作。

下面我們使用一個簡單的例子演示下如何自定義一個View對象,我們先講述下這個例子實(shí)現(xiàn)的效果:例子將展現(xiàn)一個藍(lán)色背景的面板,當(dāng)你點(diǎn)擊面板中的 某點(diǎn)時(shí)會以這個點(diǎn)擊點(diǎn)為中心隨機(jī)產(chǎn)生一個 半徑是1-10的紅色實(shí)心圓。我們首先自定義一個View對象,CustomView.java:

package com.android777.demo.uicontroller.view;
  
import java.util.ArrayList;
import java.util.List;
  
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
  
public class CustomView extends View {
  
    Paint paint;
    List<Dot> dots;
  
    public CustomView(Context context) {
        super(context);
        init();
    }
  
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
  
    public void init(){
  
        paint = new Paint();
        //設(shè)置繪制的顏色是紅色
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);
  
        //視圖對象背景色是藍(lán)色
        setBackgroundColor(Color.BLUE);
  
        //初始化時(shí)里面沒有顯示任何的紅點(diǎn)
        dots = new ArrayList<CustomView.Dot>();
    }
  
    @Override
    public boolean onTouchEvent(MotionEvent event) {
  
        //獲取隨機(jī)點(diǎn)擊位置的坐標(biāo)值
        float x = event.getX();
        float y = event.getY();
        //生成一個隨機(jī)半徑值范圍是1 - 10
        float radius = (float) (1 + Math.random() * 9);
  
        //將點(diǎn)擊的坐標(biāo)和隨機(jī)生成的半徑值構(gòu)造成Dot對象存放到視圖里
        dots.add(new Dot(x,y,radius));
  
        //掉用這個方法 重新繪制視圖, 這樣就能把上面剛添加的點(diǎn)顯示出來
        invalidate();
  
        return super.onTouchEvent(event);
    }
  
    @Override
    protected void onDraw(Canvas canvas) {
  
        //繪制所有視圖對象里保存的Dot點(diǎn)信息
        for(Dot dot : dots){
            canvas.drawCircle(dot.x, dot.y, dot.radius, paint);
        }
  
    }
  
    /**
     *
     * 這個靜態(tài)內(nèi)部類用來封裝一個紅色圓點(diǎn)的位置和半徑
     *
     */
    static class Dot {
  
        public float x;
        public float y;
        public float radius;
  
        public Dot(float x,float y,float radius){
  
            this.x = x;
            this.y = y;
            this.radius = radius;
        }
  
    }
  
}

然后我們編寫一個Activity,在里面使用上面自定義的視圖,CustomViewActivity.java:

package com.android777.demo.uicontroller.view;
  
import android.app.Activity;
import android.os.Bundle;
  
public class CustomViewActivity extends Activity {
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
  
        setContentView(new CustomView(this));
  
    }
  
}
運(yùn)行后,點(diǎn)擊屏幕中的某點(diǎn)就會產(chǎn)生一個隨機(jī)半徑范圍是1-10的紅色小實(shí)心圓:

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多