ListView中Item高度问题
2017-11-20 本文已影响566人
c263ae2147d8
-
一般情况下Item布局中写法如下
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="80dp"> <TextView android:id="@+id/tv_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="item" /> </android.support.constraint.ConstraintLayout>
-
但是上面的写法在运行之后并不能达到ListView的每个
Item
都是80dp的效果,而是所有的Item
高度自适应了,这是什么原因呢?来看看源码。ListView在layout
的时候会调用一个方法用于获取View,这个方法就是makeAndAddView(...)
,部分源码如下:private View makeAndAddView(int position, int y, boolean flow, int childrenLeft, boolean selected) { ... ... // Make a new view for this position, or convert an unused view if // possible. 获取View final View child = obtainView(position, mIsScrap); // This needs to be positioned and measured. setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]); return child; }
-
可以看到
makeAndAddView
中调用了obtainView
方法,这个方法是ListView父类AbsListView
中的方法,部分源码如下:View obtainView(int position, boolean[] outMetadata) { ... ... ... //设置Item的LayoutParams setItemViewLayoutParams(child, position); if (AccessibilityManager.getInstance(mContext).isEnabled()) { if (mAccessibilityDelegate == null) { mAccessibilityDelegate = new ListItemAccessibilityDelegate(); } if (child.getAccessibilityDelegate() == null) { child.setAccessibilityDelegate(mAccessibilityDelegate); } } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return child; }
-
再继续看setItemViewLayoutParams方法,源码如下:
private void setItemViewLayoutParams(View child, int position) { //这里的child指的是item,也就是上面xml中的 ...ConstraintLayout 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); } }
-
setItemViewLayoutParams
中的vlp
默认是为null的,所以会进入到第一个if
语句中的generateDefaultLayoutParams
方法,如下://生成一个AbsListView.LayoutParams,宽:MATCH_PARENT,高:WRAP_CONTENT protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0); }
-
generateDefaultLayoutParams
方法会生成一个宽为MATCH_PARENT
,高为WRAP_CONTENT
的AbsListView.LayoutParams
,所以你在item的xml中设置的高度没有生效,因为ListView默认给每个Item
设置了LayoutParams
-
解决方法
- 在xml里面多嵌套一次布局
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="80dp"> <TextView android:id="@+id/tv_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="item" /> </RelativeLayout> </android.support.constraint.ConstraintLayout>
- 或者在Adapter中的getView方法里面手动给convertView设置一个AbsListView.LayoutParams
@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (null == convertView) { holder = new ViewHolder(); convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_demo1, null, false); //设置convertView的LayoutParams convertView.setLayoutParams(new AbsListView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, 300) ); holder.textView = convertView.findViewById(R.id.tv_item); convertView.setTag(holder); System.out.println(convertView.getLayoutParams() == null); } else { holder = (ViewHolder) convertView.getTag(); } holder.textView.setText(list.get(position).getDesc()); return convertView; }