listView每个item之间的边距设置 ,一开始的想法是在item 的根布局设置margin 属性,但是在listView 中margin无法生效,padding是有效的,所以在此研究下失效的原因。
解决办法就是在根布局中再加一层布局, 新增根布局的下一次布局设置margin. 如果可以给根布局设置padding解决问题的话,设置padding也可
解决方法
第一种,设置padding
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_margin="30dp" //设置无效
android:padding="30dp" //设置有效
android:layout_height="match_parent">
<TextView
android:id="@+id/list_item_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
第二种 增加一层布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
//根布局下增加一层
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="30dp"
>
<TextView
android:id="@+id/list_item_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
</LinearLayout>
问题分析
对于这个问题的分析是参考博客 https://blog.csdn.net/android_freshman/article/details/52077323
layout_margin根布局失效原因:
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);
}
}
ViewGroup中有一个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;
}
}