1. 程式人生 > >android:layout_margin真實含義 及 自己定義復合控件 layout()運行無效的問題解決

android:layout_margin真實含義 及 自己定義復合控件 layout()運行無效的問題解決

== net 橫屏 應該 ima ont lan vbo protect

一、關於layout_margin

搞Android時間也不短了。對layout_margin也不陌生了,可近期遇到一個問題讓我發現,對它的認識還不夠深入全面。大量網絡資料上都說,layout_margin指view距離父view的距離。這個說法不夠嚴謹。正確的說法是。距離view的相對view的距離才更準確。

在Linearlayout下,能夠覺得是距離父view的距離。

但在RelativeLayout下則不然。假設view A已經寫定在view B的右側。則view A的layout_marginLeft就是距離view B的距離,與父View無關。另外,這個距離到底是兩個view中心的距離還是相鄰兩邊的距離?能夠這樣理解。每一個view都是一個矩形區域,假設view A已經設定在view B的右側,則layout_marginLeft是view B的右邊 和view A的左邊之間的距離,而非兩個view中心之間的距離!

示意圖例如以下:

技術分享


技術分享

二、關於自己定義復合控件layout()無效的問題

如上圖所看到的。我將一個ImageView和一個TextView組合在一起作為一個自己定義控件。然後將四個這種自己定義控件放在底部的一個RelativeLayout裏。兩邊的view,即“消息”和“設置”能夠通過設置RelativeLayout的左右padding來控制位置。可是第二個view和第三個View則須要自己來調整。

底部的這個RelativeLayout代碼例如以下:

<?xml version="1.0" encoding="utf-8"?>
<org.yanzi.ui.BottomControlPanel xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:layout_alignParentBottom="true"
    android:gravity="center_vertical"
    android:paddingLeft="20dp"
    android:paddingRight="20dp" >

    <org.yanzi.ui.ImageText
        android:id="@+id/btn_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true" />

    <org.yanzi.ui.ImageText
        android:id="@+id/btn_contacts"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/btn_message" />

    <org.yanzi.ui.ImageText
        android:id="@+id/btn_news"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/btn_contacts" />

    <org.yanzi.ui.ImageText
        android:id="@+id/btn_setting"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true" />

</org.yanzi.ui.BottomControlPanel>

這裏我將第二個view設置在第一個view的右側。第三個view在第二個的右側。這個BottomControlPanel.java也是自己定義的,繼承自RelativeLayout。為了讓四個view等間距分布,本能的想到重寫BottomControlPanel.java的onLayout()函數。註意這裏,第二個view“聯系人”的寬度要寬於其它3個view。

@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		// TODO Auto-generated method stub
		super.onLayout(changed, left, top, right, bottom);
		layoutItems(left, top, right, bottom);


		//		for(int i = 0; i< n; i++){
		//			ImageText v = viewList.get(i); //getChildAt(i);
		//			v.setVisibility(View.VISIBLE);
		//			int vTop = top;
		//			int vLeft = paddingLeft + i * (blankV + viewW);
		//			int vBottom = bottom;
		//			int vRight = vLeft + viewW;
		//			(v).layout(vLeft, vTop, vRight, vBottom);
		//			Log.i("yanzi"," vTop = " + vTop + " vLeft = " + vLeft + " vBottom = " + vBottom + " vRight = " + vRight);
		//		}


	}
	/**最左邊和最右邊的view由母布局的padding進行控制位置。這裏需對第2、3個view的位置又一次設置
	 * @param left
	 * @param top
	 * @param right
	 * @param bottom
	 */
	private void layoutItems(int left, int top, int right, int bottom){
		int n = getChildCount();
		if(n == 0){
			return;
		}
		int paddingLeft = getPaddingLeft();
		int paddingRight = getPaddingRight();
		Log.i("yanzi", "paddingLeft = " + paddingLeft + " paddingRight = " + paddingRight);
		int width = right - left;
		int height = bottom - top;
		Log.i("yanzi", "width = " + width + " height = " + height);
		int allViewWidth = 0;
		for(int i = 0; i< n; i++){
			View v = getChildAt(i);
			Log.i("yanguoqi", "v.getWidth() = " + v.getWidth());
			allViewWidth += v.getWidth();
		}
		int blankWidth = (width - allViewWidth - paddingLeft - paddingRight) / (n - 1);
		Log.i("yanzi", "blankV = " + blankWidth );

		LayoutParams params1 = (LayoutParams) viewList.get(1).getLayoutParams();
		params1.leftMargin = blankWidth;
		viewList.get(1).setLayoutParams(params1);

		LayoutParams params2 = (LayoutParams) viewList.get(2).getLayoutParams();
		params2.leftMargin = blankWidth;
		viewList.get(2).setLayoutParams(params2);
	}

最初我是使用onLayout()函數裏凝視掉的這一段來控制的:

// for(int i = 0; i< n; i++){
// ImageText v = viewList.get(i); //getChildAt(i);
// v.setVisibility(View.VISIBLE);
// int vTop = top;
// int vLeft = paddingLeft + i * (blankV + viewW);
// int vBottom = bottom;
// int vRight = vLeft + viewW;
// (v).layout(vLeft, vTop, vRight, vBottom);
// Log.i("yanzi"," vTop = " + vTop + " vLeft = " + vLeft + " vBottom = " + vBottom + " vRight = " + vRight);
// }

非常顯然,一個view的繪制過程分為:onMeasure 進行測量大小,onLayout計算放的位置,onDraw進行繪制。可是在這裏,layout()這個函數死活不起作用了。

我之前使用layout()時都是好好的,註意使用layout()時將上面代碼裏的super.onLayout(changed, left, top, right, bottom);凝視掉。本來帶super()的時候運行的是默認流程。view還能夠畫出來。

把這個super去掉。換成我自己計算的坐標layout()上。結果一個view都繪制不出來。可的的確確。對單一布局,如將這裏的ImageText換成ImageView則是能夠正常放置的,為此我又重寫了ImageText的onlayout()函數。仍然是什麽都畫不出來。

通過onLayout()打印發現。在顯示過程中共進入這裏兩次。第一次的時候view的width和height都是0。應該是還沒顯示出來,第二次時能得到width和height。(這塊描寫敘述不準確,下來還要再細致研究下)

最後為了解決這個問題,幹脆就讓它super.onLayout(),在他以下加上自己寫的layoutItems()函數。通過計算leftMargin來確定位置。於是有了上面第一個問題關於margin的精確理解。

最後問題完美解決,橫屏情況下也能正常放置:

技術分享

最後補充一點。一個view假設設置了padding,那麽view.getWidth()得到的長度是包括padding的。

layoutItems()的過程是獲得整個父view的寬度,這個寬度包括最左邊和最右邊的兩個padding。然後計算allViewWidth,即四個view的總寬度。兩者相減除以3得到這3個空檔的距離,然後把參數設下去就ok了。待我把源代碼梳理好再上傳。

android:layout_margin真實含義 及 自己定義復合控件 layout()運行無效的問題解決