1、關於layout_marginhtml
搞Android時間也不短了,對layout_margin也不陌生了,可近期遇到一個問題讓我發現,對它的認識還不夠深刻全面。大量網絡資料上都說,layout_margin指view距離父view的距離。這個說法不夠嚴謹,正確的說法是,距離view的相對view的距離才更準確。java
在Linearlayout下。可以以爲是距離父view的距離。但在RelativeLayout下則否則,假設view A已經寫定在view B的右側,則view A的layout_marginLeft就是距離view B的距離,與父View無關。android
另外。這個距離究竟是兩個view中心的距離仍是相鄰兩邊的距離?可以這樣理解,每個view都是一個矩形區域。假設view A已經設定在view B的右側。則layout_marginLeft是view B的右邊 和view A的左邊之間的距離,而非兩個view中心之間的距離。示意圖例如如下:網絡
2、關於本身定義複合控件layout()無效的問題ide
如上圖所看到的。我將一個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等間距分佈,本能的想到重寫BottomControlPanel.java的onLayout()函數。注意這裏。第二個view「聯繫人」的寬度要寬於其它3個view。post
@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進行控制位置。這裏需對第二、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);
}
// 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);
// }
ui
很是顯然,一個view的繪製過程分爲:onMeasure 進行測量大小,onLayout計算放的位置。onDraw進行繪製。但是在這裏。layout()這個函數死活不起做用了。spa
我以前使用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了。
待我把源代碼梳理好再上傳。