ScrollView中嵌套ListView只显示一行的问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huangxin388/article/details/78176903

首先要明白为什么要这样做。   

     ScrollView可以滚动,Listview也可以滚动,那么为什么要在ScrollViewh中嵌套ListView呢?

    来个例子给大家观察一下

        大家仔细观察QQ界面的布局就会发现,红色框中的内容用List View做非常简单;但是整个黑色框中整体又是可以滑动的。这样就免不了在Scroll View中嵌套List View。当然你也可以不用ListView,直接把红色框中的内容一个个做出来,不过这样未免太麻烦了吧,而且难于管理,又有失我们程序员的水准,所以我们当然会选择嵌套了。但是问题来了嵌套使用的话会使List View的高度计算有误,导致只能显示ListView中的一行内容。

解决方案大致有一下几种

一、一行代码完美搞定这个小问题

    !!!重写ListView!!!    什么!要重写控件惊恐,略过略过......

一提起重写控件或者自定义控件,一些初学者就望而却步,认为很难很难,是大神才搞的骚操作。其实不然,自定义控件非常简单,而且有固定的套路(由于不是讲自定义控件这里就不详述了)。看下面的代码好像很难,其实前三个构造函数都是重写ListView构造函数,根本不用动手敲(IDE)会自动帮你完成。只是重写了onMeasure方法,而且就增加了一行代码

int measuredHeight = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
 
 如果无法解决你的问题,多半是下一行代码需要替换一个变量,被你马虎了。 
 

public class MyList extends ListView{
    public MyList(Context context) {
        super(context);
    }

    public MyList(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyList(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredHeight = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);//只写了这一句就搞定了
        super.onMeasure(widthMeasureSpec, measuredHeight);//这里需要将第二个参数改为我们测量好的measureHeight
    }
}


然后在xml文件中引用ListView的地方改为我们自定义的MyList就可以了(注意:引用自定义控件时一定要加上完整的包名)

就像这样


            <com.example.a57278.school.MyList
                android:id="@+id/list_view"
                android:layout_width="match_parent"

                android:layout_height="match_parent">

            </com.example.a57278.school.MyList>

结果

怎么样,完美解决问题,是不是很简单呢!



二、手动设置ListView的高度

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.a57278.school.MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <ListView
                android:id="@+id/list_view"
                android:layout_width="match_parent"
                android:layout_height="100dp">

            </ListView>
        </LinearLayout>
    </ScrollView>
    
</android.support.constraint.ConstraintLayout>


这个解决办法非常完美,但也特别鸡肋。因为在开发过程中是很忌讳直接指定尺寸的,这样会导致不同分辨率,不同尺寸屏幕上显示的目标尺寸不一致,甚至导致界面十分混乱。


三、用一个ListView代替ScrollView

思路:将ScrollView中的其他部分也作为一项显示在ListView中。

只需为ScrollView中的各个部分分别建立布局


在重写BaseAdapter中的getView方法时只需要

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TrendViewHolder holder = null;
        if(convertView == null) {
            holder = new TrendViewHolder();
            if(position == 0) {
                convertView = mInflater.inflate(R.layout.list_layout_top,null);
            } else if(position == 4){
                convertView = mInflater.inflate(R.layout.list_layout_bottom,null);
            } else {
                convertView = mInflater.inflate(R.layout.list_item,null);
            }
            holder.iconView = (ImageView)convertView.findViewById(R.id.list_icon);
            holder.titleView = (TextView)convertView.findViewById(R.id.list_title);
            holder.arrowView = (ImageView)convertView.findViewById(R.id.list_arrow);
            convertView.setTag(holder);
        } else {
            holder = (TrendViewHolder) convertView.getTag();
        }
        holder.iconView.setImageBitmap(mData.get(position).getIcon());
        holder.titleView.setText(mData.get(position).getTitle());
        holder.arrowView.setImageBitmap(mData.get(position).getArrow());
        return convertView;
    }
这样根据不同的position为不同的item定制不同的布局文件就可以了。不过数据源的适配又是个大问题,因为顶部,中部和底部的数据源格式不一致(如果一致的话又何必在ScrollView中嵌套ListView)呢?


四、使用LinearLayout或RelativeLayout代替List View,将每个item的布局都写出来。分别为每个布局添加点击事件,这里就不演示了(太麻烦尴尬)。


五、动态计算ListView的高度

    public void setListViewHeightBasedOnChildren(ListView listView) {   
        // 获取ListView对应的Adapter   
        ListAdapter listAdapter = listView.getAdapter();   
        if (listAdapter == null) {   
            return;   
        }   
   
        int totalHeight = 0;   
        for (int i = 0, len = listAdapter.getCount(); i < len; i++) {   
            // listAdapter.getCount()返回数据项的数目   
            View listItem = listAdapter.getView(i, null, listView);   
            // 计算子项View 的宽高   
            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);   
    }  

代码也不难,将所有的iem高度加起来,然后再加上所有分割线的高度,将其设置为整个Listview的高度就行了。




六、设置Scroll View的属性

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

    </ScrollView>

只要设置

android:fillViewport="true"就可以了。

看其他人的帖子里面有这样写的。试了一下并不能解决我的问题。在这里提一下,万一能解决你们的 问题呢吐舌头



大家看到代码中有一些看不懂的标签或这尖括号之类的请自行略过(本来想把重要的代码高亮标出来,结果编辑器不太智能,把标签都显示出来了),万望见谅。

猜你喜欢

转载自blog.csdn.net/huangxin388/article/details/78176903
今日推荐