久久久精品一区ed2k-女人被男人叉到高潮的视频-中文字幕乱码一区久久麻豆樱花-俄罗斯熟妇真实视频

Android如何自定義View

這篇文章將為大家詳細(xì)講解有關(guān)Android如何自定義View,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括新野網(wǎng)站建設(shè)、新野網(wǎng)站制作、新野網(wǎng)頁(yè)制作以及新野網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,新野網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到新野省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!

首先,我來(lái)講講Android的控件架構(gòu)。Android的控件可以被分為兩類(lèi),分別是ViewGroup和View。在ViewGroup中可以包含多個(gè)View,并且管理他們??丶?shù)就是有這兩個(gè)部分組成的,控件樹(shù)的上層負(fù)責(zé)的是下層控件的繪制和測(cè)量以及交互。我們?cè)贏ctivity中使用的findViewById()方法,就是在控件樹(shù)中用深度遍歷的方法搜索到對(duì)應(yīng)的ID的。每一顆控件樹(shù)的頂部,都有個(gè)ViewParent對(duì)象,他是整棵樹(shù)的核心,負(fù)責(zé)調(diào)度所有的交互事件。在Activity中,我們是使用setContentView()來(lái)加載布局的。每個(gè)Activity都是包含著一個(gè)Window對(duì)象的,在Android中通常是PhoneWindow,他將一個(gè)DecorView作為整個(gè)窗口的根View,將要顯示的內(nèi)容呈現(xiàn)在window上。DecorView又分為兩個(gè)部分,一個(gè)是TitleView,一個(gè)是ContentView。ContentView是一個(gè)ID為content的Framelayout,布局文件就是設(shè)置在這里面的。而TitleView就是我們看到topbar標(biāo)題欄。這就是activity加載布局文件的過(guò)程了。

接下來(lái),我們開(kāi)始講自定義控件的使用,下面講解使用的時(shí)候,會(huì)夾帶著一些原理的分析。自定義控件可以分為三種類(lèi)型,一種是拓展谷歌提供的系統(tǒng)控件,來(lái)達(dá)到自己想要的效果。一種是將系統(tǒng)提供的控件組合在一起,作為一個(gè)組合控件來(lái)使用。還有一種是重新繪制測(cè)量一個(gè)全新的控件。

一、拓展谷歌提供的系統(tǒng)控件

假如我們要對(duì)Textview控件進(jìn)行拓展,首先我們要定義一個(gè)類(lèi)繼承TextView,選擇性的重寫(xiě)它的onDraw()、onMeasure()、onTouchEvent()等方法。其中,onDraw()負(fù)責(zé)對(duì)圖像的繪制,onMeasure()負(fù)責(zé)測(cè)量位置,onTouchEvent()負(fù)責(zé)設(shè)置觸摸的事件。當(dāng)我們想直接繪制出有背景顏色的TextView時(shí),可以在類(lèi)中定義畫(huà)筆,在onDraw()進(jìn)行繪制。代碼如下:

Paint paint1=new Paint(); //定義畫(huà)筆paint1.setColor(Color.YELLOW);paint1.setStyle(Paint.Style.FILL);

然后,通過(guò)以下的代碼,就可以繪制出一個(gè)帶矩形框的Textview,但是需要在繪制完成后在調(diào)用父類(lèi)的onDraw(),因?yàn)槭窃谙到y(tǒng)控件上拓展,所以,還要有其原來(lái)的功能。

@Override  protected void onDraw(Canvas canvas) {    canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),paint1);//繪制矩形    canvas.save();    super.onDraw(canvas);    canvas.restore();  }

使用canvas對(duì)象就可以進(jìn)行繪圖了,對(duì)canvas的講解,我將會(huì)在下一篇博客講解。

然后,我們只需要在布局文件中加入自定義的控件即可,在布局文件中,自定義view的名字就是自定義控件類(lèi)的包名加上類(lèi)名,假設(shè)定義CustomTextview類(lèi)繼承TextView,例子如下:

<com.example.myapplication.View.CustomTextView    android:layout_width="wrap_content"    android:layout_height="match_parent"></com.example.myapplication.View.Buttonbtn>

二、將系統(tǒng)提供的控件組合在一起

除了拓展原有的控件以外,我們還可以將控件組合成一個(gè)新的控件使用。首先,我們先定義一個(gè)新的布局文件,并把Imageview和Textview加入,代碼如下。

<ImageView  android:id="@+id/iv"  android:layout_width="20dp"  android:layout_height="20dp"  android:src="@mipmap/ic_launcher" /> <TextView  android:id="@+id/tv"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:layout_marginTop="2dp"  android:text="消息"  android:textSize="13sp" />

然后我們定義一個(gè)類(lèi)繼承LinearLayout,在類(lèi)的構(gòu)造方法中對(duì)控件和布局進(jìn)行初始化。

public void init(Context context) {    //指定線(xiàn)性布局的顯示方式,垂直    setOrientation(VERTICAL);    //設(shè)置用戶(hù)期望的布局方式    LayoutParams mLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);    setLayoutParams(mLayoutParams);    setGravity(Gravity.CENTER);    setPadding(4, 4, 4, 4);    //設(shè)置其布局文件    View mButtonbtnView = LayoutInflater.from(context).inflate(layout.botton_btn_view, this, true);    mImageView = mButtonbtnView.findViewById(id.iv);    mTextView = mButtonbtnView.findViewById(id.tv);  }

接下來(lái),它的使用方法就和拓展控件的方法一樣了,直接在布局文件中,加入控件即可。

<com.example.myapplication.View.Buttonbtn    android:layout_width="wrap_content"    android:layout_height="match_parent"></com.example.myapplication.View.Buttonbtn>

三、重寫(xiě)View來(lái)實(shí)現(xiàn)全新的控件

當(dāng)系統(tǒng)原生的控件無(wú)法滿(mǎn)足我們需求時(shí),我們就可以定義一個(gè)新的控件來(lái)完成需要的功能。創(chuàng)建一個(gè)新的控件,需要繼承View類(lèi),其難點(diǎn)主要在于繪制控件和實(shí)現(xiàn)交互。在繼承View類(lèi)時(shí),我們還需要重寫(xiě)它的onDraw(),onMeasure()、onTouchEvent()來(lái)實(shí)現(xiàn)繪制、測(cè)量和觸摸事件。

onDraw()繪制就是在canvas對(duì)象上調(diào)用其一系列方法進(jìn)行繪圖,繪制控件的形狀。

onMeasure()

下面,我來(lái)講講onMeasure()。在繪制View之前,我們需要告訴系統(tǒng)我們需要畫(huà)一個(gè)多大的View以及他的位置,這就是onMeasure()進(jìn)行的了。首先,我們來(lái)了解一下測(cè)量的三種模式:

EXACTLY:精確值模式,在指定view具體數(shù)值的時(shí)候會(huì)用到。

AT_MOST:最大值模式,將控件設(shè)置為"wrap_content"用到,它會(huì)根據(jù)子控件或者內(nèi)容變化而變化。

UNSPECIFIED:繪制控件想要多大就可以多大。

根據(jù)以上三種模式,我們就可以在測(cè)量的時(shí)候判斷和使用了。首先,我們重寫(xiě)一個(gè)view的onMeasure()方法。再通過(guò)使用MeasureSpec類(lèi)獲得控件的測(cè)量模式。MeasureSpec使用的是位運(yùn)算,其高2位為測(cè)量的模式,剩下的30位為測(cè)量的大小。

@Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int widthMode = MeasureSpec.getMode(widthMeasureSpec);    int widthSize = MeasureSpec.getSize(widthMeasureSpec);     if (widthMode == MeasureSpec.EXACTLY) {     } else if (widthMode == MeasureSpec.AT_MOST) {     } else if (widthMode == MeasureSpec.UNSPECIFIED) {     }   }

以上代碼就是通過(guò)判斷測(cè)量模式來(lái)給定義控件的大小,這里只是測(cè)量了控件的寬度,控件高度的測(cè)量也是類(lèi)似的,就不在做詳解。

前面說(shuō)過(guò),ViewGroup是用來(lái)管理控件的,當(dāng)ViewGroup的大小為"wrap_content"時(shí),它就會(huì)遍歷其所有子View,來(lái)獲得子View的大小,再來(lái)設(shè)置自身的大小。我們使用過(guò)的布局,像RelativeLayout,LinearLayout都是繼承ViewGroup的,所以他們也是使用這種方法來(lái)獲得自己的大小的。

onTouchEvent()

onTouchEvent()就是我們所說(shuō)的觸摸事件,由于Android手機(jī)是觸屏的,所以我們自定義View在觸摸屏幕的時(shí)候,也需要有一定的處理來(lái)完成交互。當(dāng)重寫(xiě)onTouchEvent方法的時(shí)候,我們可以看到,需要傳入MotionEvent的對(duì)象。我們可以通過(guò)這個(gè)類(lèi)來(lái)設(shè)置觸摸的事件,也可以獲得觸摸點(diǎn)的位置。我們可以通過(guò)getAction()來(lái)獲取觸摸事件的行動(dòng),來(lái)判斷是否按下屏幕或者移動(dòng)。在Android的坐標(biāo)系中,我們都知道Android的屏幕在豎屏的時(shí)候,以左上角的位置為原點(diǎn),向右為x軸的正方向,向下為y軸的正方向,知道了這個(gè)后,我們就可以通過(guò)調(diào)用getX()和getY()方法可以獲取觸摸點(diǎn)的坐標(biāo),來(lái)完成一些交互操作。

public boolean onTouchEvent(MotionEvent event) {    float x;    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:      {        x=event.getX();      }        break;      case MotionEvent.ACTION_MOVE:        break;      case MotionEvent.ACTION_UP:        break;    }    return true;  }

以上就是自定義控件常用重寫(xiě)的方法,通過(guò)了重寫(xiě)這幾個(gè)方法,我們基本就可以實(shí)現(xiàn)一個(gè)簡(jiǎn)易的自定義控件了。下面,我們來(lái)了解下控件的事件攔截機(jī)制的原理。

事件攔截機(jī)制分析

我們前面講過(guò),控件結(jié)構(gòu)是樹(shù)形結(jié)構(gòu),一個(gè)ViewGroup中可能有多個(gè)ViewGroup或者View,那么,觸摸事件是怎么準(zhǔn)確的分配給每個(gè)View和ViewGroup的呢。我們假設(shè)有一個(gè)ViewGroupA,在他的里面嵌套著ViewGroupB,而在ViewGroupB的里面,又嵌套著一個(gè)View。當(dāng)我們重寫(xiě)ViewGroupA類(lèi)的時(shí)候,就需要重寫(xiě)里面的這三個(gè)方法:

  1. dispatchTouchEvent()  onInterceptTouchEvent()  onTouchEvent()

而在重寫(xiě)View的時(shí)候,需要重寫(xiě)兩個(gè)方法:

  1. dispatchTouchEvent()  onTouchEvent()

可以根據(jù)名字看出,ViewGroup中比View多了onInterceptTouchEvent()方法,這個(gè)方法就是事件攔截的核心。在每一個(gè)方法中Log一下,再點(diǎn)擊View的時(shí)候,就會(huì)發(fā)現(xiàn)方法調(diào)用的順序:

首先,調(diào)用了ViewGroupA類(lèi)的dispatchTouchEvent()和onInterceptTouchEvent()。

再調(diào)用了ViewGroupB類(lèi)的dispatchTouchEvent()和onInterceptTouchEvent()。

再到View的dispatchTouchEvent()方法。

這個(gè)調(diào)用的順序就是事件傳遞的順序,而事件處理的順序則是:

View的onTouchEvent()。  ViewGroupB的onTouchEvent()。  ViewGroupA的onTouchEvent()。

由此,可以看出,事件的分發(fā)是由上層的ViewGroup發(fā)布的,再逐層下發(fā)。而事件的處理,則是由下層的View處理后,再逐層上傳。前面也說(shuō)過(guò),onInterceptTouchEvent()是事件攔截的核心,那么,只要設(shè)置它的返回值為true,就可以攔截事件,使其不再下發(fā),而onTouchEvent()返回false,事件處理后就不會(huì)再上傳。事件的分發(fā)和攔截的流程就大致講解完成了。

關(guān)于“Android如何自定義View”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。

本文標(biāo)題:Android如何自定義View
瀏覽地址:http://sd-ha.com/article26/jgiicg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、網(wǎng)站制作、域名注冊(cè)、網(wǎng)站建設(shè)、定制開(kāi)發(fā)、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)