作为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修改为paddingpadding不是布局参数(LayoutParam),即使填充时不指定父View,也会保留在填充后的布局中。
网友评论