android 关于listview item设置高度的问题解决方法

来源:互联网 发布:网剧数据分析 编辑:程序博客网 时间:2024/06/01 12:50

关于listview item 高度显示不正常,有时候会忘记,mark一下。转载至:coderinchina


关于listview,做andriod开发都必须知道的,我写了一个简单的adapter,在这不考虑什么缓存机制就单单为了显示一下而已:

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public class MainActivity extends Activity {  
  2.     private static final String TAG = "MainActivity" ;  
  3.     private ListView listview;  
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.content_main);  
  8.         listview = (ListView) findViewById(R.id.listview);  
  9.         listview.setAdapter(new MyAdapter());  
  10.     }  
  11.     class MyAdapter extends BaseAdapter{  
  12.         @Override  
  13.         public int getCount() {  
  14.             return 20;  
  15.         }  
  16.         @Override  
  17.         public Object getItem(int position) {  
  18.             return null;  
  19.         }  
  20.         @Override  
  21.         public long getItemId(int position) {  
  22.             return 0;  
  23.         }  
  24.         @Override  
  25.         public View getView(int position, View convertView, ViewGroup parent) {  
  26.             return View.inflate(MainActivity.this,R.layout.item,null);  
  27.         }  
  28.     }  
  29. }  
效果图:


如果想设置item的高度为某一个特定的值 比如为200dp,也许你会说很简单,这么做就搞定

<?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="300dp">    <ImageView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:src="@mipmap/ic_launcher"        />    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="今天天气真好"        android:layout_marginTop="10dp"        android:textColor="#ff00ff"        android:gravity="center"        /></LinearLayout>

但是很遗憾告诉你这样是不行的,原因在哪?

我们都知道在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"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="wrap_content"    ><LinearLayout    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="300dp">    <ImageView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:src="@mipmap/ic_launcher"        />    <TextView        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="今天天气真好"        android:layout_marginTop="10dp"        android:textColor="#ff00ff"        android:gravity="center"        /></LinearLayout></LinearLayout>
效果图:


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

0 0
原创粉丝点击