Android listview加载不同布局与adapter用法

本文介绍Android开发中ListView加载多种布局的方法。通过自定义Adapter实现了不同类型的item视图,并详细解释了getView方法中convertView的复用机制及ViewHolder模式的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android listview加载不同布局与adapter用法
android开发过程中会经常用到listview,虽然recycleview也出来了,但是还是存在一些bug没有解决,还不是特别的成熟,那我们就来介绍一下listview的使用及其加载不同布局的item的一般写法。

  1. 首先我们listview需要加载不同的布局,首先我们需要些几个不同的布局(我写不同item的布局喜欢以inflate_功能_type_one来命名,大家可以根据自己的习惯,但是一定要有一个好的编程习惯哦!!!)
    布局一:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/txt_inflat_type_one"
    android:background="#44C494"
    android:layout_width="match_parent"
    android:layout_height="40dp">
</TextView>

布局二:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:background="#ffa07a"
    android:layout_width="match_parent"
    android:layout_height="40dp">

    <TextView
        android:id="@+id/txt_inflat_type_two"
        android:layout_width="200dp"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/img_inflat_type_two"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@null"
        android:background="@mipmap/ic_launcher"/>

</LinearLayout>

布局三:

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

    <TextView
        android:id="@+id/txt_inflat_type_there_1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@+id/txt_inflat_type_there_2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>
  1. 接下来就是需要写的是MyAdapter了,我这里是继承BaseAdapter来写的,首先我们需要重写BaseAdapter的四个方法,getCount(listview需要展示的个数,根据数据源而定的,我在这里是写的规固定的)、getItem(获取数据源的单个实体类)、getItemId(获取下角标位置)、getView(UI控件的获取及其数据的挂载)。
    这里,我们需要写的是不同布局item显示的样式,我们还需要重写其他两个方法:getItemViewType(获取每一个下角标(position)相对应得item类型),getViewTypeCount(几种布局的显示的总数)。
    注意
        //listview显示时的不同布局的item
        private int TypeOne=0;//注意这个不同布局的类型起始值必须从0开始
        private int TypeTwo=1;
        private int TypeThere=2;
  1. 因为在实际开发项目中,我们要加载的数据往往是特别大的,这时候我们就要考虑布局的复用,说到复用我们就要来了解一下ListView的原理:ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,创建View对象(getLayoutInflater().inflate(R.layout.inflate_type_one, parent,false);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。Android提供了一个叫做Recycler(反复循环器)的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。

getView方法中的操作是这样的:先从xml中创建view对象(inflate操作,我们采用了重用convertView方法优化),然后在这个view去findViewById,找到每一个子View,如:一个TextView等。这里的findViewById操作是一个树查找过程,也是一个耗时的操作,所以这里也需要优化,就是使用viewHolder,把每一个子View都放在Holder中,当第一次创建convertView对象时,把这些子view找出来。然后用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。当第二次重用convertView时,只需从convertView中getTag取出来就可以。

我们就需要先写几个不同item需要的viewHolder类:

private class TypeOneViewHolder{
            private TextView txt_inflat_type_one;
        }

private class TypeTwoViewHolder{
            private TextView txt_inflat_type_two;
            private ImageView img_inflat_type_two;
        }

  private class TypeThereViewHolder{
            private TextView txt_inflat_type_there_1;
            private TextView txt_inflat_type_there_2;
        }

getView方法:

@Override
        public View getView(int position, View convertView, ViewGroup parent) {

            TypeOneViewHolder typeOneViewHolder = null;
            TypeTwoViewHolder typeTwoViewHolder = null;
            TypeThereViewHolder typeThereViewHolder = null;

            int Type=getItemViewType(position);
            //第一次没有加载convertView
            if(convertView==null){
                if(Type==TypeOne){
                    convertView=getLayoutInflater().inflate(R.layout.inflate_type_one,parent,false);
                    typeOneViewHolder=new TypeOneViewHolder();
                    typeOneViewHolder.txt_inflat_type_one= (TextView) convertView.findViewById(R.id.txt_inflat_type_one);
                    convertView.setTag(typeOneViewHolder);

                }else if(Type==TypeTwo){
                    convertView=getLayoutInflater().inflate(R.layout.inflate_type_two,parent,false);
                    typeTwoViewHolder=new TypeTwoViewHolder();
                    typeTwoViewHolder.txt_inflat_type_two= (TextView) convertView.findViewById(R.id.txt_inflat_type_two);
                    typeTwoViewHolder.img_inflat_type_two= (ImageView) convertView.findViewById(R.id.img_inflat_type_two);
                    convertView.setTag(typeTwoViewHolder);
                }else if(Type==TypeThere){
                    convertView=getLayoutInflater().inflate(R.layout.inflate_type_there,parent,false);
                    typeThereViewHolder=new TypeThereViewHolder();
                    typeThereViewHolder.txt_inflat_type_there_1= (TextView) convertView.findViewById(R.id.txt_inflat_type_there_1);
                    typeThereViewHolder.txt_inflat_type_there_2= (TextView) convertView.findViewById(R.id.txt_inflat_type_there_2);
                    convertView.setTag(typeThereViewHolder);
                }

            }else {
            //布局的复用convertView
            //根据setTag()和getTag()方法来实现布局的复用
                if(Type==TypeOne){
                    typeOneViewHolder= (TypeOneViewHolder) convertView.getTag();
                }else if(Type==TypeTwo){
                    typeTwoViewHolder= (TypeTwoViewHolder) convertView.getTag();
                }else if(Type==TypeThere){
                    typeThereViewHolder= (TypeThereViewHolder) convertView.getTag();
                }

            }

            //设置数据
            if(Type==TypeOne){
                typeOneViewHolder.txt_inflat_type_one.setText("第一种布局"+position);
            }else if(Type==TypeTwo){
                typeTwoViewHolder.txt_inflat_type_two.setText("第二种布局"+position);
                typeTwoViewHolder.img_inflat_type_two.setImageResource(R.mipmap.ic_launcher);
            }else if(Type==TypeThere){
                typeThereViewHolder.txt_inflat_type_there_1.setText("第三种布局"+position+"左");
                typeThereViewHolder.txt_inflat_type_there_2.setText("第三种布局"+position+"右");
            }

            return convertView;
        }

实现效果截图:
这里写图片描述

这里写图片描述

最后附整体代码:

package com.example.administrator.baseadapterapplication;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;


/**
 * Android listview加载不同布局与adapter用法
 *@author wujun
 *
 */

public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private MyAdapter myAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
    }

    private void initView() {
        listView= (ListView) findViewById(R.id.listview);
    }

    private void initData() {
        myAdapter=new MyAdapter(MainActivity.this);
        listView.setAdapter(myAdapter);
        myAdapter.notifyDataSetChanged();
    }


    //适配器
    private class  MyAdapter extends BaseAdapter {

        private Context mcontext;

        //listview显示时的不同布局的item
        private int TypeOne=0;//注意这个不同布局的类型起始值必须从0开始
        private int TypeTwo=1;
        private int TypeThere=2;

        private   MyAdapter(Context context){
            mcontext=context;
        }

        @Override
        public int getCount() {
            return 30;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        //item的不同布局的判断
        @Override
        public int getItemViewType(int position) {
//            return super.getItemViewType(position);
            if(position==1||position==5||position==10||position==15||position==20||position==26){
                return TypeOne;
            }else if(position==2||position==6||position==8||position==13||position==23||position==0){
                return TypeTwo;
            }else {
                return TypeThere;
            }
        }

        @Override
        public int getViewTypeCount() {
//            return super.getViewTypeCount();
            return 3;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            TypeOneViewHolder typeOneViewHolder = null;
            TypeTwoViewHolder typeTwoViewHolder = null;
            TypeThereViewHolder typeThereViewHolder = null;

            int Type=getItemViewType(position);
            if(convertView==null){
                if(Type==TypeOne){
                    convertView=getLayoutInflater().inflate(R.layout.inflate_type_one,parent,false);
                    typeOneViewHolder=new TypeOneViewHolder();
                    typeOneViewHolder.txt_inflat_type_one= (TextView) convertView.findViewById(R.id.txt_inflat_type_one);
                    convertView.setTag(typeOneViewHolder);

                }else if(Type==TypeTwo){
                    convertView=getLayoutInflater().inflate(R.layout.inflate_type_two,parent,false);
                    typeTwoViewHolder=new TypeTwoViewHolder();
                    typeTwoViewHolder.txt_inflat_type_two= (TextView) convertView.findViewById(R.id.txt_inflat_type_two);
                    typeTwoViewHolder.img_inflat_type_two= (ImageView) convertView.findViewById(R.id.img_inflat_type_two);
                    convertView.setTag(typeTwoViewHolder);
                }else if(Type==TypeThere){
                    convertView=getLayoutInflater().inflate(R.layout.inflate_type_there,parent,false);
                    typeThereViewHolder=new TypeThereViewHolder();
                    typeThereViewHolder.txt_inflat_type_there_1= (TextView) convertView.findViewById(R.id.txt_inflat_type_there_1);
                    typeThereViewHolder.txt_inflat_type_there_2= (TextView) convertView.findViewById(R.id.txt_inflat_type_there_2);
                    convertView.setTag(typeThereViewHolder);
                }

            }else {

                if(Type==TypeOne){
                    typeOneViewHolder= (TypeOneViewHolder) convertView.getTag();
                }else if(Type==TypeTwo){
                    typeTwoViewHolder= (TypeTwoViewHolder) convertView.getTag();
                }else if(Type==TypeThere){
                    typeThereViewHolder= (TypeThereViewHolder) convertView.getTag();
                }

            }

            //设置数据
            if(Type==TypeOne){
                typeOneViewHolder.txt_inflat_type_one.setText("第一种布局"+position);
            }else if(Type==TypeTwo){
                typeTwoViewHolder.txt_inflat_type_two.setText("第二种布局"+position);
                typeTwoViewHolder.img_inflat_type_two.setImageResource(R.mipmap.ic_launcher);
            }else if(Type==TypeThere){
                typeThereViewHolder.txt_inflat_type_there_1.setText("第三种布局"+position+"左");
                typeThereViewHolder.txt_inflat_type_there_2.setText("第三种布局"+position+"右");
            }

            return convertView;
        }

        private class TypeOneViewHolder{
            private TextView txt_inflat_type_one;
        }

        private class TypeTwoViewHolder{
            private TextView txt_inflat_type_two;
            private ImageView img_inflat_type_two;
        }

        private class TypeThereViewHolder{
            private TextView txt_inflat_type_there_1;
            private TextView txt_inflat_type_there_2;
        }

    }

}

大家有什么android开发问题可以一起交流(QQ:965244491 附微信二维码交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值