欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-26 23:33:57
...

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

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

    来个例子给大家观察一下

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

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

解决方案大致有一下几种

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

    !!!重写ListView!!!    什么!要重写控件ScrollView中嵌套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>

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

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



二、手动设置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中的各个部分分别建立布局

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

在重写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的布局都写出来。分别为每个布局添加点击事件,这里就不演示了(太麻烦ScrollView中嵌套ListView只显示一行的问题)。


五、动态计算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"就可以了。

看其他人的帖子里面有这样写的。试了一下并不能解决我的问题。在这里提一下,万一能解决你们的 问题呢ScrollView中嵌套ListView只显示一行的问题



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