ListView展示两种布局

关于在ListView中显示两种布局时,某次曾经出现过ViewHolder的类转换异常。解决方法是在convertView不为null时,进行holder与type的判断,如果不匹配,则将convertView设置为null。

if ((convertView != null && convertView.getTag() instanceof ViewHolder1 && type == TYPE_2)
||(convertView != null && convertView.getTag() instanceof ViewHolder2 && type == TYPE_1)) {
            convertView = null;
}

可是这次写新的demo并没有出现这种情况。相关实现方法如下。

首先需要重写getViewTypeCount与getItemViewType这两个方法,type的值必须从0开始。

    private static final int TYPE_1 = 0;
    private static final int TYPE_2 = 1;

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {
        if (position % 5 < 2) {
            return TYPE_1;
        } else {
            return TYPE_2;
        }
    }

然后就在getView中进行当前位置的判断确定是哪种类型并进行相应的加载。并提供两个ViewHolder进行不同布局的视图控制。当convertView为null时判断一次,convertView与holder绑定时判断一次,以及convertView不为null被复用时判断一次。
getView的相关代码如下:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder1 holder1 = null;
        ViewHolder2 holder2 = null;
        int type = getItemViewType(position);
        if (convertView == null) {
            switch (type) {
                case TYPE_1:
                    convertView = LayoutInflater.from(context).inflate(R.layout.list_item1,null);
                    holder1 = new ViewHolder1();
                    holder1.tvName = (TextView) convertView.findViewById(R.id.tv_name);
                    holder1.tvHabit = (TextView) convertView.findViewById(R.id.tv_habit);
                    holder1.tvAge = (TextView) convertView.findViewById(R.id.tv_age);
                    convertView.setTag(holder1);
                    break;
                case TYPE_2:
                    convertView = LayoutInflater.from(context).inflate(R.layout.list_item2,null);
                    holder2 = new ViewHolder2();
                    holder2.tvName = (TextView) convertView.findViewById(R.id.tv_name);
                    holder2.tvAge = (TextView) convertView.findViewById(R.id.tv_age);
                    convertView.setTag(holder2);
                    break;
            }
        }else{
            switch (type){
                case TYPE_1:
                    holder1 = (ViewHolder1) convertView.getTag();
                    break;
                case TYPE_2:
                    holder2 = (ViewHolder2) convertView.getTag();
                    break;
            }
        }
        People p = list.get(position);
        switch (type){
            case TYPE_1:
                holder1.tvName.setText(p.name);
                holder1.tvAge.setText(p.age+"");
                holder1.tvHabit.setText(p.habit);
                break;
            case TYPE_2:
                holder2.tvName.setText(p.name);
                holder2.tvAge.setText(p.age+"");
                break;
        }
        return convertView;
    }

供加载的两种布局:

<?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="match_parent"
    android:padding="@dimen/activity_horizontal_margin">

    <TextView
        android:id="@+id/tv_name"
        android:text="name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_habit"
        android:text="habit"
        android:layout_below="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_age"
        android:layout_below="@id/tv_habit"
        android:text="0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_alignParentRight="true"
        android:layout_alignBaseline="@id/tv_name"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@mipmap/ic_launcher"/>

</RelativeLayout>
<?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="match_parent"
    android:background="#ccc"
    android:padding="@dimen/activity_horizontal_margin">

    <TextView
        android:id="@+id/tv_name"
        android:text="name"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_age"
        android:layout_below="@id/tv_name"
        android:layout_alignParentRight="true"
        android:text="0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_alignBaseline="@id/tv_name"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:src="@mipmap/ic_launcher"/>

</RelativeLayout>

最后实现的结果:
这里写图片描述

当时出现异常的情况是:当拖动速度较快时会发生,如果慢慢的拖动则不会出现这种异常,如今不能重现这种情况了。不知道是不是当时进行网络请求的原因。希望有人能够告知一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在ListView中添加不同的动态布局,你需要在适配器中重写getView()方法。在该方法中,你可以通过position参数来判断当前的数据项需要使用哪种布局。 以下是一个简单的示例代码,假设我们有两种数据类型:TypeA和TypeB,需要在ListView中显示: ```kotlin class MyAdapter(private val context: Context, private val data: List<Any>) : BaseAdapter() { private val TYPE_A = 0 private val TYPE_B = 1 override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { var view = convertView val type = getItemViewType(position) if (view == null) { // 根据不同类型加载不同的布局 view = if (type == TYPE_A) { LayoutInflater.from(context).inflate(R.layout.layout_type_a, parent, false) } else { LayoutInflater.from(context).inflate(R.layout.layout_type_b, parent, false) } } // 根据不同类型填充数据 if (type == TYPE_A) { // 填充 Type A 的数据 val item = data[position] as TypeA // ... } else { // 填充 Type B 的数据 val item = data[position] as TypeB // ... } return view } override fun getItem(position: Int): Any { return data[position] } override fun getItemId(position: Int): Long { return position.toLong() } override fun getCount(): Int { return data.size } override fun getItemViewType(position: Int): Int { // 根据不同数据类型返回不同的类型值 return if (data[position] is TypeA) TYPE_A else TYPE_B } override fun getViewTypeCount(): Int { // 返回布局类型的数量,这里有两种类型 return 2 } } ``` 在上面的代码中,我们首先定义了两个常量TYPE_A和TYPE_B,用于表示不同的布局类型。在getView()方法中,我们根据position参数和getItemViewType()方法的返回值来判断当前数据项需要使用哪种布局。如果convertView为空,则根据不同的类型加载不同的布局。然后在各自的分支中填充数据即可。最后,我们还需要在适配器中重写getItemViewType()和getViewTypeCount()方法,用于返回布局类型和布局类型数量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值