【达内课程】ListView使用

ListView

ListView 是列表显示控件

继承结构
View
一一ViewGroup
一一一AdapterView
一一一一AbsListView
一一一一一ListView

使用ListView的要素
1、ListView的控件
容器,用于承载所有的列表项(item)

2、layout
模板,用于确定每一个列表的显示样式

3、数据的 List 集合
用于确定需要显示的数据

4、Adapter,可以是 ArrayAdapter,SimpleAdapter,BaseAdapter
用于组装数据与模板,并将组装的结果提供给listview

栗子

布局文件,注意,以下栗子中所有布局都用的这一个

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

代码中

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private ArrayAdapter<String> adapter;
    private List<String> contacts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        //初始化控件
        listView = findViewById(R.id.listview);

        //初始化List集合
        contacts = new ArrayList<>();
        contacts.add("Jimmy");
        contacts.add("Kim");
        contacts.add("Mike");
        contacts.add("Gus");

        //创建Adapter
        Context context = MainActivity.this;
        //可以使用安卓自带的布局,也可以使用自己的布局:R.layout.xx
        int textViewResourceId = android.R.layout.simple_list_item_1;
        adapter = new ArrayAdapter<>(context, textViewResourceId, contacts);

        //为ListView配置Adapter
        listView.setAdapter(adapter);
    }
}

运行结果
在这里插入图片描述

ArrayAdapter

【特点】
模板必须使用 TextView 作为根节点
【优点】
简单
【缺点】
只能显示单一的数据
【继承结构】
BaseAdapter
一一ArrayAdapter

SimpleAdapter

activity_main.xml 布局和上面相同

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private SimpleAdapter adapter;
    private List<Map<String, Object>> data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化控件
        listView = findViewById(R.id.listview);

        //创建数据
        data = new ArrayList<>();
        Map<String, Object> item1 = new HashMap<>();
        item1.put("name", "王力宏");
        item1.put("email", "wanglihong@qq.com");
        item1.put("avatar", R.mipmap.wanglihong);
        data.add(item1);
        Map<String, Object> item2 = new HashMap<>();
        item2.put("name", "王俊凯");
        item2.put("email", "wangjunkai@qq.com");
        item2.put("avatar", R.mipmap.wangjunkai);
        data.add(item2);
        Map<String, Object> item3 = new HashMap<>();
        item3.put("name", "王者荣耀");
        item3.put("email", "wangzhe@qq.com");
        item3.put("avatar", R.mipmap.wangzhe);
        data.add(item3);

        Context context = MainActivity.this;
        int resource = R.layout.item_contact;//模板资源
        String[] from = {"name", "email", "avatar"};//数据从哪来
        int[] to = {R.id.tv_name, R.id.tv_email, R.id.iv_avatar};//显示到哪个控件上

        //创建Adapter
        adapter = new SimpleAdapter(context, data, resource, from, to);

        //为listview配置Adapter
        listView.setAdapter(adapter);
    }
}

item_contact.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp">

    <ImageView
        android:id="@+id/iv_avatar"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginRight="10dp"
        android:src="@mipmap/ic_launcher" />

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

    <TextView
        android:id="@+id/tv_email"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_name"
        android:layout_toRightOf="@+id/iv_avatar"
        android:text="email" />

</RelativeLayout>

运行结果
这里写图片描述
【继承结构】
BaseAdapter
一一SimpleAdapter
【特点】
必须使用List<Map<String,?>>作为数据源
【优点】
相对简单,且能显示多种数据
【缺点】
准备数据时操作比较麻烦
模板是固定的,不可以动态调整

优化
将 Map 的键改为常量

private static final String KEY_NAME = "name";
private static final String KEY_EMAIL = "email";
private static final String KEY_AVATAR = "avatar";

Map<String,Object> item1 = new HashMap<String,Object>();
item1.put(KEY_NAME,"王力宏");
item1.put(KEY_EMAIL,"wanglihong@qq.com");
item1.put(KEY_AVATAR,R.mipmap.wanglihong);
data.add(item1);

BaseAdapter

栗子:用BaseAdapter实现上面的效果

activity_main.xml 布局和上面相同

MainActivity.xml

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private BaseAdapter adapter;
    private List<Contact> contacts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = findViewById(R.id.listview);

        contacts = new ArrayList<Contact>();
        contacts.add(new Contact("王力宏", "wanglihong@qq.com", R.mipmap.wanglihong));
        contacts.add(new Contact("王俊凯", "wangjunkai@qq.com", R.mipmap.wangjunkai));
        contacts.add(new Contact("王者荣耀", "wangzhe@qq.com", R.mipmap.wangzhe));

        adapter = new ContactAdapter(MainActivity.this, contacts);
        listView.setAdapter(adapter);
    }
}

Contact

public class Contact {
    private String name;
    private String email;
    private int imageResId;

    public Contact(String name, String email, int imageResId) {
        this.name = name;
        this.email = email;
        this.imageResId = imageResId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getImageResId() {
        return imageResId;
    }

    public void setImageResId(int imageResId) {
        this.imageResId = imageResId;
    }
}

ContactAdapter

public class ContactAdapter extends BaseAdapter {
    //数据源
    private List<Contact> contacts;
    private Context context;

    public ContactAdapter(Context context, List<Contact> contacts) {
        this.context = context;
        this.contacts = contacts;
    }

    @Override
    public int getCount() {
        //【功能】返回数据源的数据量,即有多少条数据
        return contacts.size();
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        //【功能】返回已经组装了数据的列表项的view对象
        //1、确定要被显示的数据
        Contact contact = contacts.get(i);
        //获取模板的view对象
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflater.inflate(R.layout.item_contact, null);

        ImageView imgAvanter = v.findViewById(R.id.iv_avatar);
        TextView tv_name = v.findViewById(R.id.tv_name);
        TextView tv_email = v.findViewById(R.id.tv_email);

        imgAvanter.setImageResource(contact.getImageResId());
        tv_name.setText(contact.getName());
        tv_email.setText(contact.getEmail());

        return v;
    }

    @Override
    public Object getItem(int i) {
        //无视
        return null;
    }

    @Override
    public long getItemId(int i) {
        //无视
        return 0;
    }
}

item_contact.xml 同上

注意:
1、ListView 使用时,高度应该是固定值,match_parent 或者一个固定的 dp 值的高度,不能是 wrap_content
2、Android 在绘制 Adapter 时,系统首先调用 getCount() 方法,根据它的返回值得到 ListView 的长度,然后根据这个长度,调用 getView() 方法逐行绘制。如果 ListView 的长度超过了屏幕的长度,Android 只会绘制显示出来的 Item,同时,系统会回收走隐藏的 Item。

优化ListView

每次的 getview 都会创建 view 对象,对象创建多了使用的内存会更大,会有内存溢出的危险,因此优化 ContactAdapter 如下

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        Log.d("ListView", "getView" + i);

        //【功能】返回已经组装了数据的列表项的view对象
        //1、确定要被显示的数据
        Contact contact = contacts.get(i);

        if (view == null) {
            //加载第一屏的列表时
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.item_contact, null);
        } else {
            //有列表项已经滑出屏幕,view表示离开屏幕的列表项的View对象,可以用于显示后面没新的进入屏幕的列表项
        }

        //获取模板的view对象
        ImageView imgAvanter = view.findViewById(R.id.iv_avatar);
        TextView tv_name = view.findViewById(R.id.tv_name);
        TextView tv_email = view.findViewById(R.id.tv_email);

        imgAvanter.setImageResource(contact.getImageResId());
        tv_name.setText(contact.getName());
        tv_email.setText(contact.getEmail());

        return view;
    }

这样不会反复创建 view 对象,节省内存开支

使用 ListView实现联系人列表

在这里插入图片描述

【方法1】

activity_main.xml 布局同上

item_contact.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_sort"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#AAAAAA"
        android:padding="5dp"
        android:text="A"
        android:textColor="#ffffff" />

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_sort"
        android:padding="5dp"
        android:text="name" />

</RelativeLayout>

Contact

public class Contact implements Comparable<Contact>{
   private String name;
   private String pinyin;

    public Contact(String name,String pinyin) {
        this.name = name;
        this.pinyin = pinyin;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPinyin() {
        return pinyin;
    }

    public void setPinyin(String pinyin) {
        this.pinyin = pinyin;
    }

    @Override
    public int compareTo(@NonNull Contact contact) {
        return pinyin.compareTo(contact.pinyin);
    }
}

MainActivity

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private ContactAdapter adapter;
    private List<Contact> contacts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = findViewById(R.id.listview);

        contacts = new ArrayList<>();
        contacts.add(new Contact("许家印", "xujiayin"));
        contacts.add(new Contact("马化腾", "mahuateng"));
        contacts.add(new Contact("马云家族", "mayun"));
        contacts.add(new Contact("杨惠妍", "yagnhuiyan"));
        contacts.add(new Contact("王健林家族", "wangjianlin"));
        contacts.add(new Contact("王卫", "wangwei"));
        contacts.add(new Contact("李彦宏、马东敏夫妇", "liyanhong"));
        contacts.add(new Contact("何享健、何剑锋父子", "hetingjian"));
        contacts.add(new Contact("严昊", "yanhao"));
        contacts.add(new Contact("丁磊", "dinglei"));
        contacts.add(new Contact("李书福、李星星父子", "lishufu"));
        contacts.add(new Contact("张志东", "zhangzhidong"));
        contacts.add(new Contact("宗庆后家族", "zongqinghou"));
        contacts.add(new Contact("姚振华", "yaozhenhua"));
        contacts.add(new Contact("张近东", "zhangjindong"));
        contacts.add(new Contact("卢志强家族", "luzhiqiang"));
        contacts.add(new Contact("王文银、刘结红夫妇", "wangwenyin"));
        contacts.add(new Contact("严彬", "yanbin"));
        contacts.add(new Contact("孙宏斌", "sunhongbin"));
        contacts.add(new Contact("周群飞、郑俊龙夫妇", "zhouqunfei"));
        contacts.add(new Contact("刘强东", "liuqiangdong"));
        contacts.add(new Contact("雷军", "leijun"));
        //对数据进行排序,必须使得List集合内部的数据类型实现Comparable接口
        Collections.sort(contacts);

        adapter = new ContactAdapter(MainActivity.this, contacts);

        listView.setAdapter(adapter);
    }
}

ContactAdapter

public class ContactAdapter extends BaseAdapter {
    private List<Contact> data;
    private Context context;

    public ContactAdapter(Context context, List<Contact> data) {
        this.context = context;
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.item_contact, null);
        }

        TextView tv_name = view.findViewById(R.id.tv_name);
        TextView tv_sort = view.findViewById(R.id.tv_sort);

        tv_name.setText(data.get(i).getName());
        tv_sort.setText(data.get(i).getPinyin().toUpperCase().charAt(0) + "");

        //判断是否显示分类字母
        //1、如果是第一条数据,显示分类字母
        //2、如果不是第一条数据,则和上一条数据对比,相同,不显示。不相同,显示
        if (i == 0) {
            tv_sort.setVisibility(View.VISIBLE);
        } else {
            char lastSortKey = data.get(i - 1).getPinyin().toUpperCase().charAt(0);
            char currentSortKey = data.get(i).getPinyin().toUpperCase().charAt(0);

            if (lastSortKey == currentSortKey) {
                tv_sort.setVisibility(View.GONE);
            } else {
                tv_sort.setVisibility(View.VISIBLE);
            }
        }
        return view;
    }

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

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

【方法2】

只修改 ContactAdapter

public class ContactAdapter extends BaseAdapter implements SectionIndexer {
    private List<Contact> data;
    private Context context;

    public ContactAdapter(Context context, List<Contact> data) {
        this.context = context;
        this.data = data;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.item_contact, null);
        }

        TextView tv_name = view.findViewById(R.id.tv_name);
        TextView tv_sort = view.findViewById(R.id.tv_sort);

        tv_name.setText(data.get(i).getName());
        tv_sort.setText(data.get(i).getPinyin().toUpperCase().charAt(0) + "");

        //如果第几位(应该出现在的位置)的首字母出现在的位置,和当前位置相等,则显示,否则不显示
        if (i == getPositionForSection(getSectionForPosition(i))) {
            tv_sort.setVisibility(View.VISIBLE);
        } else {
            tv_sort.setVisibility(View.GONE);
        }

        return view;
    }

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

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

    @Override
    public Object[] getSections() {
        return new Object[0];
    }

    @Override
    public int getPositionForSection(int section) {
        //获取section对应的position
        //获取某个分类字母应该在列表中出现在第几位
        for (int i = 0; i < data.size(); i++) {
            int currentSection = getSectionForPosition(i);
            if (currentSection == section) {
                return i;
            }
        }
        return 0;
    }

    @Override
    public int getSectionForPosition(int position) {
        //获取参数position对应的section
        //获取第几个位置上应该显示的字母
        return data.get(position).getPinyin().toUpperCase().charAt(0);
    }
}

改进:联系人增加字母索引

在这里插入图片描述
activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ListView
        android:id="@+id/lv_section"
        android:layout_width="20dp"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:divider="@null" />

</RelativeLayout>

item_section.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="14sp" />

MainActivity

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private ContactAdapter adapter;
    private List<Contact> contacts;
    //Section的数据源
    private String[] sections;
    private ListView lv_section;
    private ArrayAdapter adapter_section;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Section的ListView
        lv_section = findViewById(R.id.lv_section);
        //创建Section数据
/*        sections = new String[26];
        for(int i=0;i<sections.length;i++){
            sections[i]=""+((char)'A'+i);
        }*/
        sections = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".split(",");
        //Section的Adapter
        adapter_section = new ArrayAdapter<String>(MainActivity.this, R.layout.item_selection, sections);
        lv_section.setAdapter(adapter_section);

        InnerClassOnItemClickListener listener = new InnerClassOnItemClickListener();
        lv_section.setOnItemClickListener(listener);

        listView = findViewById(R.id.listview);

        contacts = new ArrayList<>();
        contacts.add(new Contact("许家印", "xujiayin"));
        contacts.add(new Contact("马化腾", "mahuateng"));
        contacts.add(new Contact("马云家族", "mayun"));
        contacts.add(new Contact("杨惠妍", "yagnhuiyan"));
        contacts.add(new Contact("王健林家族", "wangjianlin"));
        contacts.add(new Contact("王卫", "wangwei"));
        contacts.add(new Contact("李彦宏、马东敏夫妇", "liyanhong"));
        contacts.add(new Contact("何享健、何剑锋父子", "hetingjian"));
        contacts.add(new Contact("严昊", "yanhao"));
        contacts.add(new Contact("丁磊", "dinglei"));
        contacts.add(new Contact("李书福、李星星父子", "lishufu"));
        contacts.add(new Contact("张志东", "zhangzhidong"));
        contacts.add(new Contact("宗庆后家族", "zongqinghou"));
        contacts.add(new Contact("姚振华", "yaozhenhua"));
        contacts.add(new Contact("张近东", "zhangjindong"));
        contacts.add(new Contact("卢志强家族", "luzhiqiang"));
        contacts.add(new Contact("王文银、刘结红夫妇", "wangwenyin"));
        contacts.add(new Contact("严彬", "yanbin"));
        contacts.add(new Contact("孙宏斌", "sunhongbin"));
        contacts.add(new Contact("周群飞、郑俊龙夫妇", "zhouqunfei"));
        contacts.add(new Contact("刘强东", "liuqiangdong"));
        contacts.add(new Contact("雷军", "leijun"));
        //对数据进行排序,必须使得List集合内部的数据类型实现Comparable接口
        Collections.sort(contacts);

        adapter = new ContactAdapter(MainActivity.this, contacts);

        listView.setAdapter(adapter);
    }

    private class InnerClassOnItemClickListener implements AdapterView.OnItemClickListener {
        @Override
        public void onItemClick(
                AdapterView<?> adapterView, //操作哪个listview
                View view,//操作的是哪个列表项A/B...
                int i,//操作的操作项的位置
                long l//操作的列表项的id,该值由BaseAdapter中的long getItemId()方法返回
        ) {
            //【功能】点击某个字母,使得联系人列表快速定位到指定位置
            //获取点击的字母
            int selection = sections[i].charAt(0);
            //获取点击的字母该出现的位置
            int pos = adapter.getPositionForSection(selection);
            //快速定位到pos位置
            listView.setSelection(pos);
        }
    }
}

其他不变

现在存在一个问题是,如果点击不存在的字母会返回顶部,让我们来看一下为什么会出现这个问题。让 ListView 跳转的代码是

listView.setSelection(pos);

而 pos 的值是由下面代码决定的

adapter.getPositionForSection(selection);

getPositionForSection 是默认返回 0 的。而setSelection(0)当然就返回顶部了。

ContactAdapter 的 getPositionForSection 修改如下

 public static final int NO_SUCH_SECTION = -1;

    @Override
    public int getPositionForSection(int section) {
        //获取section对应的position
        //获取某个分类字母应该在列表中出现在第几位
        for (int i = 0; i < data.size(); i++) {
            int currentSection = getSectionForPosition(i);
            if (currentSection == section) {
                return i;
            }
        }
        return NO_SUCH_SECTION;
    }

MainActivity 的

listView.setSelection(pos);

改为

//快速定位到pos位置
if (pos != ContactAdapter.NO_SUCH_SECTION) {
	listView.setSelection(pos);
}

这样当点击不存在的字母时,列表会不动。

让 ListView 滚动还有一个方法listView.smoothScrollToPosition(pos);,效果是是平缓的滑动

改进:联系人只显示存在字母

在这里插入图片描述

ContactAdapter 的 getSections 方法修改如下

@Override
    public Object[] getSections() {
        String[] sections = null;
        //使用TreeSet保存所有分类字母
        TreeSet<String> strings = new TreeSet<>();
        for (int i = 0; i < data.size(); i++) {
            int section = getSectionForPosition(i);
            strings.add("" + (char) section);
        }
        sections = new String[strings.size()];
        //遍历Set集合,向数组中的元素赋值
        int i = 0;
        for (String string : strings) {
            sections[i] = string;
            i++;
        }
        return sections;
    }

MainActivity 修改如下,主要是 sections 的赋值修改,和代码顺序修改

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private ContactAdapter adapter;
    private List<Contact> contacts;
    //Section的数据源
    private String[] sections;
    private ListView lv_section;
    private ArrayAdapter adapter_section;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lv_section = findViewById(R.id.lv_section);
        InnerClassOnItemClickListener listener = new InnerClassOnItemClickListener();
        lv_section.setOnItemClickListener(listener);

        listView = findViewById(R.id.listview);

        contacts = new ArrayList<>();
        contacts.add(new Contact("许家印", "xujiayin"));
        contacts.add(new Contact("马化腾", "mahuateng"));
        contacts.add(new Contact("马云家族", "mayun"));
        contacts.add(new Contact("杨惠妍", "yagnhuiyan"));
        contacts.add(new Contact("王健林家族", "wangjianlin"));
        contacts.add(new Contact("王卫", "wangwei"));
        contacts.add(new Contact("李彦宏、马东敏夫妇", "liyanhong"));
        contacts.add(new Contact("何享健、何剑锋父子", "hetingjian"));
        contacts.add(new Contact("严昊", "yanhao"));
        contacts.add(new Contact("丁磊", "dinglei"));
        contacts.add(new Contact("李书福、李星星父子", "lishufu"));
        contacts.add(new Contact("张志东", "zhangzhidong"));
        contacts.add(new Contact("宗庆后家族", "zongqinghou"));
        contacts.add(new Contact("姚振华", "yaozhenhua"));
        contacts.add(new Contact("张近东", "zhangjindong"));
        contacts.add(new Contact("卢志强家族", "luzhiqiang"));
        contacts.add(new Contact("王文银、刘结红夫妇", "wangwenyin"));
        contacts.add(new Contact("严彬", "yanbin"));
        contacts.add(new Contact("孙宏斌", "sunhongbin"));
        contacts.add(new Contact("周群飞、郑俊龙夫妇", "zhouqunfei"));
        contacts.add(new Contact("刘强东", "liuqiangdong"));
        contacts.add(new Contact("雷军", "leijun"));
        //对数据进行排序,必须使得List集合内部的数据类型实现Comparable接口
        Collections.sort(contacts);

        adapter = new ContactAdapter(MainActivity.this, contacts);

        sections = (String[]) adapter.getSections();
        adapter_section = new ArrayAdapter<String>(MainActivity.this, R.layout.item_selection, sections);
        lv_section.setAdapter(adapter_section);

        listView.setAdapter(adapter);
    }

    private class InnerClassOnItemClickListener implements AdapterView.OnItemClickListener {
        @Override
        public void onItemClick(
                AdapterView<?> adapterView, //操作哪个listview
                View view,//操作的是哪个列表项A/B...
                int i,//操作的操作项的位置
                long l//操作的列表项的id,该值由BaseAdapter中的long getItemId()方法返回
        ) {
            //【功能】点击某个字母,使得联系人列表快速定位到指定位置
            //获取点击的字母
            int selection = sections[i].charAt(0);
            //获取点击的字母该出现的位置
            int pos = adapter.getPositionForSection(selection);
            //快速定位到pos位置
            if (pos != ContactAdapter.NO_SUCH_SECTION) {
                listView.smoothScrollToPosition(pos);
            }
        }
    }
}

ListView Kotlin 版本讲解

写一个 Kotlin 版本,用来显示水果列表

class MainActivity :AppCompatActivity() {
    private val data = listOf("Apple","Banana","Orange","Watermelon","Pear","Grape",
                                "Pineapple","Strawberry","Cherry","Mango",
                                "Apple","Banana","Orange","Watermelon","Pear","Grape",
                                "Pineapple","Strawberry","Cherry","Mango")

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val adapter = ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data)
        listView.adapter = adapter
    }
}

定制 ListView 界面
新建 Fruit 类

class Fruit(val name:String,val imageId:Int)

新建自定义布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp">

    <ImageView
        android:id="@+id/fruitImage"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"/>
    <TextView
        android:id="@+id/fruitName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_gravity="center_vertical"/>
</LinearLayout>

新建 FruitAdapter 类

class FruitAdapter(activity:Activity,val resourceId:Int,data:List<Fruit>):
                    ArrayAdapter<Fruit>(activity,resourceId,data){
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = LayoutInflater.from(context).inflate(resourceId,parent,false)
        val fruitImage:ImageView = view.findViewById(R.id.fruitImage)
        val fruitName:TextView = view.findViewById(R.id.fruitName)
        val fruit = getItem(position)
        if(fruit != null){
            fruitImage.setImageResource(fruit.imageId)
            fruitName.setText(fruit.name)
        }
        return view
    }
}

MainActivity

class MainActivity :AppCompatActivity() {
   private val fruitList = ArrayList<Fruit>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initFruits()//初始化水果数据
        val adapter = FruitAdapter(this,R.layout.item_fruit,fruitList)
        listView.adapter = adapter
    }

    private fun initFruits(){
        repeat(3){
            fruitList.add(Fruit("Apple",R.drawable.apple))
            fruitList.add(Fruit("Banana",R.drawable.banana))
            fruitList.add(Fruit("Orange",R.drawable.orange))
            fruitList.add(Fruit("Watermelon",R.drawable.watermelon))
        }
    }
}

在这里插入图片描述

提升 ListView 的运行效率

在 FruitAdapter 中的 getView() 方法中,每次都将布局重新加载了一遍,当 ListView 快速滚动时,就会成为性能的瓶颈。getView() 方法中还有一个 convertView 参数,用于将之前加载好的布局进行缓存,以便重用

class FruitAdapter(activity:Activity,val resourceId:Int,data:List<Fruit>):
                    ArrayAdapter<Fruit>(activity,resourceId,data){
    inner class ViewHoler(val fruitImage:ImageView,val fruitName:TextView)

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view:View
        val viewHoler:ViewHoler
        if(convertView == null){
            view = LayoutInflater.from(context).inflate(resourceId,parent,false)
            val fruitImage:ImageView = view.findViewById(R.id.fruitImage)
            val fruitName:TextView = view.findViewById(R.id.fruitName)
            viewHoler = ViewHoler(fruitImage,fruitName)
            view.tag = viewHoler
        }else{
            view = convertView
            viewHoler = view.tag as ViewHoler
        }


        val fruit = getItem(position)
        if(fruit != null){
            viewHoler.fruitImage.setImageResource(fruit.imageId)
            viewHoler.fruitName.setText(fruit.name)
        }
        return view
    }
}

增加点击事件

listView.setOnItemClickListener { parent, view, position, id ->
	val fruit = fruitList[position]
	Toast.makeText(this,fruit.name,Toast.LENGTH_SHORT).show()
}

虽然我们必须在 Lambda 表达式中声明 4 个参数,但实际上却只用到了 position 这一个参数。针对这种情况,Kotlin 允许我们将没有用到的参数使用下划线替代,所以下面这种写法是合理且推荐的:

listView.setOnItemClickListener { _, _, position, _ ->
	val fruit = fruitList[position]
	Toast.makeText(this,fruit.name,Toast.LENGTH_SHORT).show()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值