View與ViewGroup
Android中的View與我們以前理解的“視圖”不同疚鲤。
在Android中,View比視圖具有更廣的含義征懈,它包含了用戶交互和顯示石咬,更像Windows操作系統(tǒng)中的window揩悄。
ViewGroup是View的子類卖哎,所以它也具有View的特性,但它主要用來充當(dāng)View的容器删性,將其中的View視作自己的孩子亏娜,對它的子View進行管理,當(dāng)然它的孩子也可以是ViewGroup類型蹬挺。
ViewGroup(樹根)和它的孩子們(View和ViewGroup)以樹形結(jié)構(gòu)形成了一個層次結(jié)構(gòu)维贺,View類有接受和處理消息的功能,android系統(tǒng)所產(chǎn)生的消息會在這些ViewGroup和 View之間傳遞巴帮。
View繪制 和 ViewGroup繪制的區(qū)別
View ViewGroup
Measure onMeasure onMeasure
Layout onLayout
Draw onDraw
當(dāng)繼承一個ViewGroup的時候 必須重寫一個方法 onLayout 傳入?yún)?shù)
(boolean changed, int l, int t, int r, int b)含義
view跟父容器的距離 l 左邊距離父容器左邊的距離 t view的上邊距離父容器上邊的距離
r view的右邊距離父容器左邊的距離 b view的下邊距離父容器上邊的距離
從寫了這個onLayout之后 需要調(diào)用它的每一個子view的layout方法 為這個子View分配一個現(xiàn)實的空間 如果不調(diào)用子view的layout方法
這個子View在Viewgroup中沒有顯示
只有當(dāng)子View的layout方法調(diào)用之后 才可以通過view.getHeight 和 view.getWidth獲取這個view的寬高
這個寬高 是父容器在layout階段設(shè)置的值
如果在layout階段之前想獲取view的測量高度和寬度
需要主動調(diào)用view.measure方法 view.measure(0,0)
測完之后 可以獲取到 測量高度和測量寬度
view.getMeasuredHeight()
view.getMeasuredWidth();
自定義一個MyViewGroup extends ViewGroup:
package test.pgl.com.a_onlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
/**
* Created by Administrator on 2017/5/28.
*/
public class MyViewGroup extends ViewGroup {
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
}
布局代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="test.pgl.com.a_onlayout.MainActivity">
<TextView android:layout_width="wrap_content"
android:textSize="20dp"
android:layout_height="wrap_content"
android:text="Hello World!" />
<test.pgl.com.a_onlayout.MyViewGroup
android:background="#999"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:textColor="#ff00"
android:textSize="20dp"
android:layout_height="wrap_content"
android:text="Hello --World!" />
</test.pgl.com.a_onlayout.MyViewGroup>
</LinearLayout>
一個原生一個自定義 進行比較:
運行:
發(fā)現(xiàn)自定義看不見:
這是因為在重寫的onLayout方法中沒有去給孩子指定空間(大小) 指定位置;
然而不知道孩子這個控件有大,直接給個位置大小不合適:
所以重寫onMeasure(Measure:測量)方法:
測量出孩子控件的大小,在onLayout方法中給他指定空間(大小) 指定位置
重寫onMeasure(Measure:測量)方法 注意一點:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//因為MyViewGroup中就一個子控件所以得到它的View對象:
View childView = getChildAt(0);
int height = childView.getHeight();
int width = childView.getWidth();
//調(diào)用measure方法對這個View進行測量 傳入0,0 意思 就是不對測量做影響 直接返回大小
Toast.makeText(getContext(), "height="+ height +" width="+ width, Toast.LENGTH_SHORT).show();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
要想獲取子控件的大小得:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//因為MyViewGroup中就一個子控件所以得到它的View對象:
View childView = getChildAt(0);
// int height = childView.getHeight();
// int width = childView.getWidth();
//調(diào)用measure方法對這個View進行測量 傳入0,0 意思 就是不對測量做影響 直接返回大小
childView.measure(0,0);
int height = childView.getMeasuredHeight();
int width = childView.getMeasuredWidth();
Toast.makeText(getContext(), "height="+ height +" width="+ width, Toast.LENGTH_SHORT).show();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
將寬高在布局中指定:
package test.pgl.com.a_onlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
/**
* Created by Administrator on 2017/5/28.
*/
public class MyViewGroup extends ViewGroup {
private int height;
private int width;
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View childView = getChildAt(0);
childView.layout(0,0,width,height);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//因為MyViewGroup中就一個子控件所以得到它的View對象:
View childView = getChildAt(0);
// int height = childView.getHeight();
// int width = childView.getWidth();
//調(diào)用measure方法對這個View進行測量 傳入0,0 意思 就是不對測量做影響 直接返回大小
childView.measure(0,0);
height = childView.getMeasuredHeight();
width = childView.getMeasuredWidth();
Toast.makeText(getContext(), "height="+ height +" width="+ width, Toast.LENGTH_SHORT).show();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
運行:
還有一個注意的地方:
package test.pgl.com.a_onlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
/**
* Created by Administrator on 2017/5/28.
*/
public class MyViewGroup extends ViewGroup {
private int height;
private int width;
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View childView = getChildAt(0);
int height1 = childView.getHeight();
int width1 = childView.getWidth();
Log.e("MyViewGroup","height1=="+height1+" width1=="+width1+" layout之前");
childView.layout(0,0,width,height);
int height2 = childView.getHeight();
int width2 = childView.getWidth();
Log.e("MyViewGroup","height2=="+height1+" width2=="+width1+" layout之后");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//因為MyViewGroup中就一個子控件所以得到它的View對象:
View childView = getChildAt(0);
// int height = childView.getHeight();
// int width = childView.getWidth();
// 這里的 height width是onLayout中賦值后的值
//調(diào)用measure方法對這個View進行測量 傳入0,0 意思 就是不對測量做影響 直接返回大小
childView.measure(0,0);
height = childView.getMeasuredHeight();
width = childView.getMeasuredWidth();
Toast.makeText(getContext(), "height="+ height +" width="+ width, Toast.LENGTH_SHORT).show();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
運行:
05-28 11:27:10.039 5922-5922/test.pgl.com.a_onlayout E/MyViewGroup: height1==0 width1==0 layout之前
05-28 11:27:10.039 5922-5922/test.pgl.com.a_onlayout E/MyViewGroup: height2==0 width2==0 layout之后
05-28 11:27:10.050 5922-5922/test.pgl.com.a_onlayout E/MyViewGroup: height1==71 width1==316 layout之前
05-28 11:27:10.051 5922-5922/test.pgl.com.a_onlayout E/MyViewGroup: height2==71 width2==316 layout之后