原文地址:http://blog.csdn.net/qinjuning/article/details/7110211
1.自定義ViewGroup
//自定義ViewGroup 對象
public class MyViewGroup extends ViewGroup{
private static String TAG = "MyViewGroup" ;
private Context mContext ;
public MyViewGroup(Context context) {
super(context);
mContext = context ;
init() ;
}
//xml定義的屬性,需要該構造函數
public MyViewGroup(Context context , AttributeSet attrs){
super(context,attrs) ;
mContext = context ;
init() ;
}
//爲MyViewGroup添加三個子View
private void init(){
//調用ViewGroup父類addView()方法添加子View
//child 對象一 : Button
Button btn= new Button(mContext) ;
btn.setText("I am Button") ;
this.addView(btn) ;
//child 對象二 : ImageView
ImageView img = new ImageView(mContext) ;
img.setBackgroundResource(R.drawable.icon) ;
this.addView(img) ;
//child 對象三 : TextView
TextView txt = new TextView(mContext) ;
txt.setText("Only Text") ;
this.addView(txt) ;
//child 對象四 : 自定義View
MyView myView = new MyView(mContext) ;
this.addView(myView) ;
}
@Override
//對每個子View進行measure():設置每子View的大小,即實際寬和高
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
//通過init()方法,我們爲該ViewGroup對象添加了三個視圖 , Button、 ImageView、TextView
int childCount = getChildCount() ;
Log.i(TAG, "the size of this ViewGroup is ----> " + childCount) ;
Log.i(TAG, "**** onMeasure start *****") ;
//獲取該ViewGroup的實際長和寬 涉及到MeasureSpec類的使用
int specSize_Widht = MeasureSpec.getSize(widthMeasureSpec) ;
int specSize_Heigth = MeasureSpec.getSize(heightMeasureSpec) ;
Log.i(TAG, "**** specSize_Widht " + specSize_Widht+ " * specSize_Heigth *****" + specSize_Heigth) ;
//設置本ViewGroup的寬高
setMeasuredDimension(specSize_Widht , specSize_Heigth) ;
for(int i=0 ;i<childCount ; i++){
View child = getChildAt(i) ; //獲得每個對象的引用
child.measure(50, 50) ; //簡單的設置每個子View對象的寬高爲 50px , 50px
//或者可以調用ViewGroup父類方法measureChild()或者measureChildWithMargins()方法
//this.measureChild(child, widthMeasureSpec, heightMeasureSpec) ;
}
}
@Override
//對每個子View視圖進行佈局
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
//通過init()方法,我們爲該ViewGroup對象添加了三個視圖 , Button、 ImageView、TextView
int childCount = getChildCount() ;
int startLeft = 0 ;//設置每個子View的起始橫座標
int startTop = 10 ; //每個子View距離父視圖的位置 , 簡單設置爲10px吧 。 可以理解爲 android:margin=10px ;
Log.i(TAG, "**** onLayout start ****") ;
for(int i=0 ;i<childCount ; i++){
View child = getChildAt(i) ; //獲得每個對象的引用
child.layout(startLeft, startTop, startLeft+child.getMeasuredWidth(), startTop+child.getMeasuredHeight()) ;
startLeft =startLeft+child.getMeasuredWidth() + 10; //校準startLeft值,View之間的間距設爲10px ;
Log.i(TAG, "**** onLayout startLeft ****" +startLeft) ;
}
}
//繪圖過程Android已經爲我們封裝好了 ,這兒只爲了觀察方法調用程
protected void dispatchDraw(Canvas canvas){
Log.i(TAG, "**** dispatchDraw start ****") ;
super.dispatchDraw(canvas) ;
}
protected boolean drawChild(Canvas canvas , View child, long drawingTime){
Log.i(TAG, "**** drawChild start ****") ;
return super.drawChild(canvas, child, drawingTime) ;
}
}
2.自定義View
主要是重寫onDraw()方法 ,
//自定義View對象
public class MyView extends View{
private Paint paint = new Paint() ;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyView(Context context , AttributeSet attrs){
super(context,attrs);
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
//設置該View大小爲 80 80
setMeasuredDimension(50 , 50) ;
}
//存在canvas對象,即存在默認的顯示區域
@Override
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Log.i("MyViewGroup", "MyView is onDraw ") ;
//加粗
paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
paint.setColor(Color.RED);
canvas.drawColor(Color.BLUE) ;
canvas.drawRect(0, 0, 30, 30, paint);
canvas.drawText("MyView", 10, 40, paint);
}
}
主Activity只是顯示了該xml文件,在此也不羅嗦了。 大家可以查看該ViewGroup的Log仔細分析下View的繪製流程以及相關方法的使用。第一次啓動後捕獲的Log如下,網上找了些資料,第一次View樹繪製過程會走幾遍,具體原因可能是某些View 發生了改變,請求重新繪製,但這根本不影響我們的界面顯示效果 。