Android自己定義組件系列【1】——自己定義View及ViewGroup

來源:互聯網
上載者:User

標籤:定位   scrollto   count()   prot   不能   mod   tran   xtend   視圖   

View類是ViewGroup的父類,ViewGroup具有View的全部特性。ViewGroup主要用來充當View的容器。將當中的View作為自己孩子,並對其進行管理。當然孩子也能夠是ViewGroup類型。

View類一般用於畫圖操作,重寫它的onDraw方法,但它不能夠包括其它組件,沒有addView(View view)方法。

ViewGroup是一個組件容器,它能夠包括不論什麼組件,但必須重寫onLayout(boolean changed,int l,int t,int r,int b)和onMesure(int widthMesureSpec,int heightMesureSpec)方法. 否則ViewGroup中加入組件是不會顯示的。

package com.example.testrefreshview;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.ViewGroup;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(new MyViewGroup(this));}public class MyViewGroup extends ViewGroup {public MyViewGroup(Context context) {super(context);Button button1 = new Button(context);button1.setText("button1");Button button2 = new Button(context);button2.setText("button2");TextView textView = new TextView(context);textView.setText("textView");addView(button1);addView(button2);addView(textView);}@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3,int arg4) {}}}

View的layout(int left,int top,int right,int bottom)方法負責把該view放在參數指定位置,所以如果我們在自己定義的ViewGroup::onLayout中遍曆每個子view並用view.layout()指定其位置。每個子View又會調用onLayout,這就構成了一個遞迴調用的過程

如果在ViewGroup中重寫onDraw方法。須要在構造方法中調用this.setWillNoDraw(flase); 此時,系統才會調用重寫過的onDraw(Canvas cancas)方法。否則系統不會調用onDraw(Canvas canvas)方法.

將上面代碼改動一下,就能夠顯示出來。

package com.example.testrefreshview;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(new MyViewGroup(this));}public class MyViewGroup extends ViewGroup {public MyViewGroup(Context context) {super(context);Button button1 = new Button(context);button1.setText("button1");Button button2 = new Button(context);button2.setText("button2");TextView textView = new TextView(context);textView.setText("textView");addView(button1);addView(button2);addView(textView);}@Overrideprotected void onLayout(boolean arg0, int arg1, int arg2, int arg3,int arg4) {int childCount = getChildCount();int left = 0;int top = 10;for (int i = 0; i < childCount; i++) {View child = getChildAt(i);child.layout(left, top, left + 60, top + 60);top += 70;}}}}

再看一段代碼:

@Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {            int childCount = getChildCount();  //設定該ViewGroup的大小      int specSize_width = MeasureSpec.getSize(widthMeasureSpec);      int specSize_height = MeasureSpec.getSize(heightMeasureSpec);       setMeasuredDimension(specSize_width, specSize_height);            for (int i = 0; i < childCount; i++) {          View childView = getChildAt(i);          childView.measure(80, 80);      }  }  

通過重寫onMeasure方法不但能夠為ViewGroup指定大小,還能夠通過遍曆為每個子View指定大小。在自己定義ViewGroup中加入上面代碼為ViewGroup中的每個子View分配了顯示的寬高。 

以下我們讓子View動起來吧。加入代碼例如以下:

public boolean onTouchEvent(MotionEvent ev) {final float y = ev.getY();switch(ev.getAction()) {case MotionEvent.ACTION_DOWN:mLastMotionY = y;break; case MotionEvent.ACTION_MOVE:int detaY = (int)(mLastMotionY - y);mLastMotionY = y;scrollBy(0, detaY);break; case MotionEvent.ACTION_UP:break;}return true;}

在上面用到了一個scrollBy方法,開啟官方API能夠看到View類有例如以下兩個方法:


這兩個函數貌似都是行動裝置檢視的。那麼它們有什麼差別呢?帶著這個疑問我們向下看

首先 ,我們必須明確在Android View視圖是沒有邊界的,Canvas是沒有邊界的,僅僅只是我們通過繪製特定的View時對 Canvas對象進行了一定的操作。比如 : translate(平移)、clipRect(剪下)等,以便達到我們的對該Canvas對象繪製的要求 。我們能夠將這樣的無邊界的視圖稱為“視圖座標”-----它不受物理螢幕限制。通常我們所理解的一個Layout布局檔案僅僅是該視圖的顯示地區,超過了這個顯示地區將不能顯示到父視圖的地區中 ,相應的,我們能夠將這樣的有邊界的視圖稱為“布局座標”------ 父視圖給子視圖分配的布局(layout)大小。並且, 一個視圖的在螢幕的起始座標位於視圖座標起始處。例如以所看到的。


由於布局座標僅僅能顯示特定的一塊內容。所以我們僅僅有移動布局座標的座標原點就能夠將視圖座標的不論什麼位置顯示出來。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical"    android:background="#888888"><TextView    android:id="@+id/txt"    android:layout_width="300dip"    android:layout_height="120dip"    android:background="#cccccc"    android:text="textview" /><Button    android:id="@+id/btn"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="button" /></LinearLayout>

當我點擊按鈕觸發事件後例如以下:


上面代碼中觸發點擊事件後,運行了textView.scrollTo(-200, -100);scrollTo中的兩個參數的含義不是座標位置。而是相對於視圖座標位置的位移量,如果我們要移動到(200,100)的位置則位移量為(0,0)-(200,100) = (-200。 -100)。

如果我們將上面代碼換成scrollBy則會發現點擊多次按鈕後textview就會移出可見介面,這是由於scrollBy是相對我們當前座標進行位移。

以下我們來看看源碼中對這兩個方法是怎樣實現的:

    /**     * Set the scrolled position of your view. This will cause a call to     * {@link #onScrollChanged(int, int, int, int)} and the view will be     * invalidated.     * @param x the x position to scroll to     * @param y the y position to scroll to     */    public void scrollTo(int x, int y) {        if (mScrollX != x || mScrollY != y) {            int oldX = mScrollX;            int oldY = mScrollY;            mScrollX = x;            mScrollY = y;            invalidateParentCaches();            onScrollChanged(mScrollX, mScrollY, oldX, oldY);            if (!awakenScrollBars()) {                invalidate(true);            }        }    }
能夠看到 mScrollX = x; mScrollY = y; 

    /**     * Move the scrolled position of your view. This will cause a call to     * {@link #onScrollChanged(int, int, int, int)} and the view will be     * invalidated.     * @param x the amount of pixels to scroll by horizontally     * @param y the amount of pixels to scroll by vertically     */    public void scrollBy(int x, int y) {        scrollTo(mScrollX + x, mScrollY + y);    }
能夠看到 mScrollX + x, mScrollY + y;

mScrollX和mScrollY是相對於視圖座標的當前位移量。







Android自己定義組件系列【1】——自己定義View及ViewGroup

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.