標籤:定位 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