最近根據設計圖寫listView 的時候,listView個item 之間存在間距,左右上下都有,一開始的想法是在item 的根佈局 設置margin 屬性,但是在listView 中margin 無法生效,所以在此研究下失效的原因。而解決辦法就是在加一層佈局,作爲根佈局 設置padding ,或者 新增根佈局的下一次佈局設置margin.
爲什麼設置margin不起作用呢?
這是我看到的一段解釋,
The fact is that, the margin of LinearLayout (child) asks its parent layout (container) to give child layout a margin of x value.
So if the parent layouts’ LayoutParams support the margins then that margin is honored and applied.
ListView uses AbsListView.LayoutParams by default, which doesn’t include any margin support, just the height and width, thats why, it simply ignores the params value for margins.
ListView extends AbsListView 查看 AbsListView 如何加入佈局參數的
private void setItemViewLayoutParams(View child, int position) {
final ViewGroup.LayoutParams vlp = child.getLayoutParams(); //直接使用子佈局的佈局參數
LayoutParams lp;
if (vlp == null) {
lp = (LayoutParams) generateDefaultLayoutParams();
} else if (!checkLayoutParams(vlp)) {
lp = (LayoutParams) generateLayoutParams(vlp);
} else {
lp = (LayoutParams) vlp;
}
if (mAdapterHasStableIds) {
lp.itemId = mAdapter.getItemId(position);
}
lp.viewType = mAdapter.getItemViewType(position);
lp.isEnabled = mAdapter.isEnabled(position);
if (lp != vlp) {
child.setLayoutParams(lp);
}
}
有一個MarginLayoutParams,ViewGroup中的margin參數有這個類計算
在ViewGroup有一個測量子類Margin的方法measureChildWithMargins
protected void measureChildWithMargins(View child,
int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width); //---------獲取margin參數-----------
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+ heightUsed, lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
在ListView的父類AbsListView中沒有實現這個類,不會計算子控件的Margin.所以在ListView的ItemView設置Margin是無效的。
padding有效的原因
下面是AblistView的onMeasure , 裏面對selection的padding邊距進行了處理。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mSelector == null) {
useDefaultSelector();
}
final Rect listPadding = mListPadding;
listPadding.left = mSelectionLeftPadding + mPaddingLeft;
listPadding.top = mSelectionTopPadding + mPaddingTop;
listPadding.right = mSelectionRightPadding + mPaddingRight;
listPadding.bottom = mSelectionBottomPadding + mPaddingBottom;
// Check if our previous measured size was at a point where we should scroll later.
if (mTranscriptMode == TRANSCRIPT_MODE_NORMAL) {
final int childCount = getChildCount();
final int listBottom = getHeight() - getPaddingBottom();
final View lastChild = getChildAt(childCount - 1);
final int lastBottom = lastChild != null ? lastChild.getBottom() : listBottom;
mForceTranscriptScroll = mFirstPosition + childCount >= mLastHandledItemCount &&
lastBottom <= listBottom;
}
}