ListView被嵌套在ScrollView里面

实际开发中,有需要用到ScrollView嵌套ListView的情况,这里就不解释为什么会用到这两种控件嵌套使用,总之这两种控件直接嵌套使用会出现问题,一般情况下出现的问题是listview的内容显示不全,它的滚动与ScrollView的滚动冲突

解决方案如下:

(1)自定义ListView,重写onMeasure()方法:

public class MyListViews extends ListView {
    public MyListViews(Context context) {
        super(context);
    }
    public MyListViews(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public MyListViews(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

上面代码的详解:http://blog.csdn.net/hanhailong726188/article/details/46136569,注意链接的文章最后一句:实际开发当中不管listview有多少条数据,都能一次性展现出来。

(2)手动设置ListView的高度

经过测量发现如果xml中指定ListView的高度是可以解决这个问题的,但是ListView的高度是可变的,所以实际使用中还需要在代码中测量后手动的设置ListView的高度,在setAdapter之后调用下面的方法就可以了。

/**
 * 动态设置ListView组建的高度
 */
public void setListViewHeightBasedOnChildren(ListView listView) {
    if (listView == null) {
        return;
    }
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        return;
    }
    int totalHeight = 0;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        View listItem = listAdapter.getView(i, null, listView);
        listItem.measure(0, 0);
        totalHeight += listItem.getMeasuredHeight();
    }
    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight
            + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
    // listView.getDividerHeight()获取子项间分隔符占用的高度
    // params.height最后得到整个ListView完整显示需要的高度
    listView.setLayoutParams(params);
}
  但是这个方法有个两个细节需要注意:
  一是Adapter中getView方法返回的View的必须由LinearLayout组成,因为只有LinearLayout才有measure()方法,如果使用其他的布局如RelativeLayout,在调用listItem.measure(0,0);时就会抛异常,因为除LinearLayout外的其他布局的这个方法就是直接抛异常的。

  二是该方法使用于每一个item的高度是固定的,或者说内容能够很快就加载完成的情况。

比如我item就只是显示一张图片,item控件的高度使用自适应(wrap_content),在adapter里面加载图片的时候,使用的是ImageLoad去加载网络图片,由于是异步加载图片,所以在setAdapter之后就开始测量高度,测出来的高度不是实际的高度,而是item的图片的高度,比如我item的图片设置了默认值,那么测出来的高度就是默认图片的高度,入股没有设置默认值,那么测出来的高度就是0,所以手动设置高度在这种情况下,会出现显示不全或者多出一些空白来。

这种方法适用于item中的图片等控件的高度是确定值(比如80dp);也适用于控件高度不确定,但是内容是很快就加载出来的那种,比如用的图片是drawable里面的图片,这种情况能够测量出准确的高度。


以上两种方法是大多人都采用的,打开一个页面,会直接显示listview的内容,所以需要手动的把Scrollview滚动到最顶端mScrollView.smoothScrollTo(0,0);也可以直接让ListView失去焦点

mListView.setFocusable(false);
我是用了很久,才发现当加载很多网络图片的时候,会出现listview的尾部多一下空白,或者加载不全。如果出现这种情况,建议使用下面一种。


(3)放弃,选择ListView加载header,footer来实现同样的效果

headLayout=getLayoutInflater().inflate(R.layout.detail_listview_head,null);
coverListView= (ListView) findViewById(R.id.listview_toshow_cover);
coverListView.addHeaderView(headLayout);
这种对于加载网络图片等不确定高度的情况也适用,不会出现listview的尾部空白也不会出现加载不全



从内存使用,来谈谈上面的方法:

方法1和2会马上就加载完给adapter的所有内容,比如我传给adapter的数据有15条,那么他们会立即加载完这15条,之后的滚动,内存会持平,不会有所增减。

方法3就是原始态的ListView了,所以它加载数据的时候不会一次性加载完,而是加载用户看到的和即将要看到,这样对于内存更好一点,用户不看到的就不占用内存。

不过方法3在优化了ViewHolder之后,可能会出现内容错位的情况。

网上找了很多方法,并不适合我的程序,所以,考虑到我的item布局就一张图片,所以省去了item中ImageView的优化,每次都findviewById:

 @Override
    public View getView(int position, View view, ViewGroup parent) {
        ViewHoder viewHoder;
        if (view == null) {
            viewHoder = new ViewHoder();
            view = inflater.inflate(R.layout.item_detail_image_listview, null);
//            viewHoder.image = (ImageView) view.findViewById(R.id.image_item);
            view.setTag(viewHoder);
        } else {
            viewHoder = (ViewHoder) view.getTag();
        }
        viewHoder.image = (ImageView) view.findViewById(R.id.image_item);
        String str = list.get(position);
        if (str != null && !str.equals("")) {
            ImageLoader.getInstance().displayImage(DBManager.IMAGE_PATH_SYSTEM + str, viewHoder.image, DB_OPTIONS);
        }
        return view;
    }

这个解决了错位的问题,不过不是最优的,以后找到更好的再来更新。

有人说ImageLoad不会出现错位,这个我也不清楚,当时测试的时候会出现,过了一段时间,发现不出现错位,暂时不清楚原因。


如果不是有ImageLoad加载图片,解决重复使用是这样解决的:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    if(convertView == null){
        convertView = mInflater.inflate(R.layout.item_listview,null);
        holder = new ViewHolder();
        holder.imageView = (ImageView) convertView.findViewById(R.id.item_img);
        holder.textView = (TextView) convertView.findViewById(R.id.item_tv);
        convertView.setTag(holder);
    }else {
        holder = (ViewHolder) convertView.getTag();
    }

    holder.textView.setText(position+"");
    final ImageView imageView = holder.imageView;
    imageView.setTag(position+"");
    imageView.setImageDrawable(null);
    //前两个显示图片
    if(position < 2) {
        //模仿耗时操作,延迟1秒
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //获得组件当前的tag,与传入的内容比较,一直的才能显示
                if(imageView.getTag().equals(position+"")) {
                    imageView.setImageBitmap(mBitmap);
                }
            }
        }, 1000);
    }
    return convertView;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值