关于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



更多相关文章

  1. Android的常用方法(转载)
  2. @BindView问题 Attempt to invoke virtual method 'void android
  3. Android(安卓)Vibrate
  4. Android(安卓)Studio 中setOnClickListener出错
  5. Android(安卓)使用 HTTPS
  6. 实现调用android URLConnection封装后快速下载,并且可以获取到实
  7. Android(安卓)Studio中AspectJ的简单使用一(自定义PointCut)
  8. Android(安卓)EditText 不弹出输入法总结
  9. android 判断EditText中输入的值是数字、字母还是汉字的方法

随机推荐

  1. Android消息推送机制
  2. 生成release版本的Android系统
  3. Json解析速度比较-Android API、Gson、Fa
  4. Android引导界面设计之ParallaxViewPager
  5. Android、iOS添加子视图方法比较
  6. Android开发板串口(SerialPort)通信
  7. Android屏幕自适应
  8. 中国开始与Android较劲
  9. Android消息机制之Handler
  10. 浅谈iOS和Android系统版本的迭代