美文网首页
ListView填充子View时为什么丢失了宽高

ListView填充子View时为什么丢失了宽高

作者: 愈强 | 来源:发表于2020-10-02 00:21 被阅读0次

作为Android开发,在做ListView相关的开发时,可能会遇到这样的问题:我辛辛苦苦写的item布局,结果在提供给ListView时丢失了宽高等信息,效果惨不忍睹,就像下面这样:

惨不忍睹的Item效果

这里item的布局文件很简单,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:textSize="14sp" />

</RelativeLayout>

可以看到,根节点上设置了80dp的高度,而实际的显示效果中的高度显然不是80dp,而是wrap_content。

为什么会这样呢?我们先来看一下填充View的代码:

// 出现异常的代码示例
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.list_item, null);
    }

    TextView textView = convertView.findViewById(R.id.text);
    textView.setText(items[position]);

    return convertView;
}

如果平时注意一下代码警告,应该就能看到在inflate方法的第二个参数上会有这样的提示:


参数警告

也就是说,要想解析待填充View的根节点的layout参数,就需要指定一个父节点(view root)。调研一下代码可以发现,此时convertView的LayoutParams是空的:


LayoutParams为空

我们来修改一下inflate这一行的代码,给他传递一个父View:

convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.list_item, parent, false);

需要注意一定要给inflate方法的第三个参数传递false。可以思考一下为什么。

运行一下,可以看到效果已经达到了预期:


image.png

通常情况下我们不希望使用固定的Item高度,而是希望使用margin定义布局的边界。接下来我们修改一下布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="16dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="16dp"
    android:layout_marginBottom="8dp">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:textSize="14sp" />

</RelativeLayout>

这里将高度定义为了wrap_content并增加了四周的边界。

运行一下看看,结果又回到了最初的样子:


加了margin后不生效

这又是什么原因呢?前面说了,填充View的时候需要提供一个父View,这样才能生成LayoutParams,这也说明了LayoutParams是和View的父View关联的。先来看一下View填充之后得到的LayoutParams对象具体是什么:

查看生成的LayoutParams对象

这个LayoutParams对象的类型是AbsListView.LayoutParams,是在ListView的父类中定义的(ListView本身并没有定义LayoutParams对象)。再仔细看AbsListView.LayoutParams这个类,发现它是直接继承自ViewGroup.LayoutParams,也就是说并不支持margin参数。(支持margin参数的类是ViewGroup.MarginLayoutParams,)

原因找到了,那么解决办法也就有了。这里不支持margin参数,那么我们只能用padding了。下面是将margin修改为padding之后的效果:

将margin修改为padding

padding不是布局参数(LayoutParam),即使填充时不指定父View,也会保留在填充后的布局中。

相关文章

网友评论

      本文标题:ListView填充子View时为什么丢失了宽高

      本文链接:https://www.haomeiwen.com/subject/uhupuktx.html