android 关于listview item设置高度的问题解决方法
16lz
2021-01-24
关于listview,做andriod开发都必须知道的,我写了一个简单的adapter,在这不考虑什么缓存机制就单单为了显示一下而已:
public class MainActivity extends Activity { private static final String TAG = "MainActivity" ; private ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.content_main); listview = (ListView) findViewById(R.id.listview); listview.setAdapter(new MyAdapter()); } class MyAdapter extends BaseAdapter{ @Override public int getCount() { return 20; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { return View.inflate(MainActivity.this,R.layout.item,null); } }}
效果图: 如果想设置item的高度为某一个特定的值 比如为200dp,也许你会说很简单,这么做就搞定
<?xml version="1.0" encoding="utf-8"?>xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="300dp"> android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> android:layout_width="match_parent" android:layout_height="wrap_content" android:text="今天天气真好" android:layout_marginTop="10dp" android:textColor="#ff00ff" android:gravity="center" />
但是很遗憾告诉你这样是不行的,原因在哪?
我们都知道在xml中带layout_xxx这样的最后都会封装成LayoutParam 这个是父view决定给子view的宽度和高度,我们到ListView的源码中
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft, boolean selected) { View child; if (!mDataChanged) { // Try to use an existing view for this position child = mRecycler.getActiveView(position); if (child != null) { // Found it -- we're using an existing child // This just needs to be positioned setupChild(child, position, y, flow, childrenLeft, selected, true); return child; } } // Make a new view for this position, or convert an unused view if possible child = obtainView(position, mIsScrap); // This needs to be positioned and measured setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]); return child;}这是listview 添加和计算每个item的方法 在AbsListView中有个obtainView()方法,
View obtainView(int position, boolean[] isScrap) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView"); isScrap[0] = false; // Check whether we have a transient state view. Attempt to re-bind the // data and discard the view if we fail. final View transientView = mRecycler.getTransientStateView(position); if (transientView != null) { final LayoutParams params = (LayoutParams) transientView.getLayoutParams(); // If the view type hasn't changed, attempt to re-bind the data. if (params.viewType == mAdapter.getItemViewType(position)) { final View updatedView = mAdapter.getView(position, transientView, this); // If we failed to re-bind the data, scrap the obtained view. if (updatedView != transientView) { setItemViewLayoutParams(updatedView, position); mRecycler.addScrapView(updatedView, position); } } isScrap[0] = true; // Finish the temporary detach started in addScrapView(). transientView.dispatchFinishTemporaryDetach(); return transientView; } final View scrapView = mRecycler.getScrapView(position); final View child = mAdapter.getView(position, scrapView, this); if (scrapView != null) { if (child != scrapView) { // Failed to re-bind the data, return scrap to the heap. mRecycler.addScrapView(scrapView, position); } else { isScrap[0] = true; // Finish the temporary detach started in addScrapView(). child.dispatchFinishTemporaryDetach(); } } if (mCacheColorHint != 0) { child.setDrawingCacheBackgroundColor(mCacheColorHint); } if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } 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(child, position);
这个方法的源码:
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); if (lp != vlp) { child.setLayoutParams(lp); }}主要的逻辑在这几行代码
if (vlp == null) { lp = (LayoutParams) generateDefaultLayoutParams();} else if (!checkLayoutParams(vlp)) { lp = (LayoutParams) generateLayoutParams(vlp);} else { lp = (LayoutParams) vlp;}第一个if是判断这个params是否等于null,等于null的话就给它一个默认的,默认的是这个
@Overrideprotected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0);}接着上面的分析 第二个if判断
!checkLayoutParams(vlp)
@Overrideprotected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof AbsListView.LayoutParams;}查看这个是不是
AbsListView.LayoutParams类型的 很显然我们没有对它做任何的事 显然不是这个类型的,那么系统会给他创建一个
@Overrideprotected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p);}
这就是为什么我们在xml中设置高度无效的原因,因为它在底层已经给我们设置了,你在外面设置导致无效
解决这个问题有二种办法:
1:在xml外层套一层布局,
<?xml version="1.0" encoding="utf-8"?>效果图:xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" > android:orientation="vertical" android:layout_width="match_parent" android:layout_height="300dp"> android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" /> android:layout_width="match_parent" android:layout_height="wrap_content" android:text="今天天气真好" android:layout_marginTop="10dp" android:textColor="#ff00ff" android:gravity="center" />
2:
在adapter中的getView()方法中添加这个
@Overridepublic View getView(int position, View convertView, ViewGroup parent) { View view = View.inflate(MainActivity.this,R.layout.item,null); AbsListView.LayoutParams param = new AbsListView.LayoutParams(300,200); view.setLayoutParams(param); return view;}
搞定,OK
更多相关文章
- Android的常用方法(转载)
- @BindView问题 Attempt to invoke virtual method 'void android
- Android(安卓)Vibrate
- Android(安卓)Studio 中setOnClickListener出错
- Android(安卓)使用 HTTPS
- 实现调用android URLConnection封装后快速下载,并且可以获取到实
- Android(安卓)Studio中AspectJ的简单使用一(自定义PointCut)
- Android(安卓)EditText 不弹出输入法总结
- android 判断EditText中输入的值是数字、字母还是汉字的方法