zoukankan      html  css  js  c++  java
  • Android ListView 常用技巧总结

    本文对 ListView 中的一些常用技巧做一个总结。附:虽然现在 RecyclerView 已逐渐取代 ListView,但实际情况是大部分项目中还在使用 ListView。当然,后续我会在我的博客中详细介绍 RecyclerView,敬请期待。

    前言

    ListView 作为 Android 中常用的列表控件,用以向用户展示列表信息。可以说,我们开发的项目中 listView 随处可见,也是 Android 程序员面试时,最常被问的一个知识点,下面我就将 listView 中的常用技巧一一罗列出来。

    listView 的缓存机制以及 ViewHolder 的使用

    这两个知识点是最常用的优化 listView 的技巧。

    1.首先,来说说 listView 的缓存机制,再这之前,我们先看看下面这张图:

    我先来说一下这张图的意思,从左边第一张图开始,当我们的手机上显示一个 listView 列表的时候,如图有 7 个 item,当我们向上拖动 listView,进入第二个示意图,注意细节,第二个图例表示的是,当向上拖动时,这是 item00 正准备消失在手机屏幕上但还没有完全消失时,item07 出现在我们的视野内,这时,item07 也只是显示一半,这种情况下,item07 还不是从缓存中复用的 item,而是重新 new 的一个 View.我们继续向上拖动,到了第三个图例,这时 item00 已经完全消失在屏幕上,这时系统不会销毁这 item00,而是将其放到了缓存中,那么当我们继续向上滑动时,我们就可以利用 listView 的 缓存机制,复用缓存中 item,用它显示 item08,而不是再次的重新 new 一个.

    2.通过 缓存机制 和 ViewHolder 配合使用

    知道了 缓存机制,我们还需要知道 ViewHolder,这时 Google 大会上推荐我们使用的 listView 优化方案。

    我们知道,我们通常写的视图 xml 文件,实际上是一个 DOM 树结构,而 findViewById() 实际上是遍历整个视图树,当你的 listView 中的 item 非常复杂时,findViewById() 所需的时间就越长,这是非常耗性能的。

    1
    2
    3
    4
    5
    6
    static class  {

    TextView title;
    ImageView img;

    }

    我们可以在第一次创建 listView 中的 item 的同时,创建一个 ViewHolder,将需要遍历的视图保存在其中,通过 View.setTag() 保存在缓存中,这样下次重用的时候就避免的再次 findViewById() 的操作了。

    注意:这样做虽然消耗了一些内存,但是与 findViewById() 遍历所需的时间相比,显得微不足道。(据测试,使用 ViewHolder,效率提高 50%)

    3.示例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;
    // 判断是否存在缓存
    if (convertView == null) {
    convertView = this.mInflater.inflate(R.layout.item_lv_weixn_about, null);

    viewHolder = new ViewHolder(convertView);
    convertView.setTag(viewHolder);
    } else {
    // 若有,取出缓存中存放的 ViewHolder,避免再次 findViewById().
    viewHolder = (ViewHolder) convertView.getTag();
    }

    // 更新视图
    viewHolder.title.setText(mStrArr[position]);

    return convertView;
    }

    设置 listView 中的分割线

    通过 android:dividerandroid:dividerHeight 这两个属性,我们可以设置设置分割线。另外,除了为分割线设置颜色以外,我们还可以为其设置图片资源:

    1
    2
    android:divider="@drawable:split_pic"
    android:dividerHeight="1dp"

    隐藏 listView 的滚动条

    我们在拖动 listView 时,默认情况下是有滚动条的,我们可以通过设置 scrollbars 属性来控制滚动条的状态。

    1
    android:scrollbars="none"

    设置为 none,则不会出现滚动条。

    取消 listView 的 item 的点击效果

    listView 默认下,但我们点击其中的 item 时,会有点击效果。通过设置 listSelector 属性来取消点击效果。

    1
    android:listSelector="#00000000"

    你还可以使用 Android 自带的透明色来实现这个效果:

    1
    android:listSelector="@android:color/transparent"

    设置 listView 需要显示在其中某一项

    listView 默认情况下是显示在第一项的,有时候,需求是显示在指定项,那么要如何实现呢?

    代码控制:

    1
    listView.setSelection(position)

    通过制定 position,来设置需要显示在第几项。但是,这种滑动操作是瞬间完成的,有时候,我们的需求是 平滑 的滑动到某个位置,通过下面的代码可以实现这种效果:

    1
    2
    3
    mListView.smoothScrollBy(distance, duration);
    mListView.smoothScrollByOffset(offset);
    mListView.smoothScrollToPosition(index);

    动态修改 listView

    listView 中的数据通常情况下,在做了某种操作后,需要动态更新,如何实现这种功能呢

    通过更新 listView 中的数据源,一般情况下都是一个 List<Object>,我们通过向 list 中添加数据,然后调用 mAdapter.notifyDataSetChanged() 方法,就能实现 listView 的动态更新了。

    1
    2
    mData.add("info");
    mAdapter.notifyDataSetChanged();

    遍历 listView 中的 item

    通过 getChildAt() 来获取某个 View:

    1
    2
    3
    for (int i = 0; i< mListView.getChildCount(); i++=) {
    View view = mListView.getChildAt(i);
    }

    交互,当 listView 为空时

    当我们 listView 加载数据为空时,列表就是空白一片,这一点对于用户体验是不好的,应该给用户以提示。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android=大专栏  Android ListView 常用技巧总结">"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"/>


    <ImageView
    android:id="@+id/empty_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/empty_image"
    />

    </FrameLayout>

    这里,我们使用一张 数据为空 的图片,当 listView 为空时,就显示这张 数据为空 的图片,通过以下代码可以达到这种效果:

    1
    2
    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setEmptyView(findViewById(R.id.empty_view));

    listView 滑动监听

    滑动监听是 listView 非常重要的技巧,我们通常需要监听不同的事件,来做不同的逻辑处理。通常情况下,我们还需要借助 GestureDetector 手势识别,VelocityTracker 滑动速度监测等。比如说,下拉刷新,快速滑动不异步加载图片等等。

    下面我们介绍两种 listView 滑动事件的方法:

    1.OnTouchListener

    OnTouchListener 是 View 中的监听事件,我们可以用来监听 ACTION_DOWN, ACTION_MOVE, ACTION_UP 这三个事件发生的坐标,从而得知用户滑动的方向,做相应的逻辑处理,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    mListView.setOnTouchListener(new View.OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
    // 触摸时,调用这里
    break;
    case MotionEvent.ACTION_MOVE:
    // 移动时,调用这里
    break;
    case MotionEvent.ACTION_UP:
    // 手指离开触摸屏时,调用这里
    break;

    }
    return false;
    }
    });

    2.OnScrollListener

    OnScrollListener 是 AbsListView 中定义的监听事件,它封装了很多与 ListView 相关的信息。我们先看看 OnScrollListener 的一般使用方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    mListView.setOnScrollListener(new AbsListView.OnScrollListener() {

    public void onScrollStateChanged(AbsListView view, int scrollState) {
    switch (scrollState) {
    case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
    // 滑动停止时,调用这里
    break;
    case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
    // 正在滚动时,调用这里
    break;
    case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
    // 手指猛地滑动调用,由于惯性,在手指离开后,还会继续滑动一段距离
    break;
    }
    }


    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    // 滚动时会一直调用这里
    }
    });

    看上面的代码,我们知道 OnScrollListener 中定义了两个回调方法,分别是:

    • 1.onScrollStateChanged()
    • 2.onScroll()

    先说说 onScrollStateChanged(),我们可以看到参数 scrollState 对应三种模式:

    • 1.OnScrollListener.SCROLL_STATE_IDLE : 滚动停止时;
    • 2.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL : 正在滚动时;
    • 3.OnScrollListener.SCROLL_STATE_FLING : 用力滑动。

    注意,但我们没有用力滑动时,这个方法只会调用 2 次,否则调用 3 次,差别就是 OnScrollListener.SCROLL_STATE_FLING 这个模式。

    再来看看 onScroll() 这个回调,它会在 listView 滚动时一直调用,方法中的 3 个参数准确的显示了当前 listView 的滚动的状态:

    • 1.firstVisibleItem : 当前能够看见的第一个 item 的 ID;
    • 2.visibleItemCount : 当前能看见的 item 的总数;
    • 3.totalItemCount : 整个 listView 中 item 的总数;

    通过这几个参数,我们能很方便的判断出是否滚动到了最后一行,代码如下:

    1
    2
    3
    if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
    // 滑动到了最后一行
    }

    我们还可以通过代码来判断滚动的方向:

    1
    2
    3
    4
    5
    6
    if (firstVisibleItem > lastVisibleItemPosition) {
    // 上滑
    } else if (firstVisibleItem < lastVisibleItemPosition) {
    // 下滑
    }
    lastVisibleItemPosition = firstVisibleItem; // 记录上次滑动时,第一个 item 的 ID

    另外,listView 还提供了一些封装的方法来获取当前可视的 item 的相关信息:

    1
    2
    3
    4
    // 获取屏幕区域内的第一个 item 的 id
    mListView.getFirstVisiblePosition();
    // 获取屏幕区域内的最后一个 item 的 id
    mListView.getLastVisiblePosition();

    本文参考:

  • 相关阅读:
    docker指令汇总
    springboot(八) 嵌入式Servlet容器自动配置原理和容器启动原理
    RabbitMQ 消息确认机制
    RabbitMQ 最常用的三大模式
    RabbitMQ 核心概念
    RabbitMQ 之简单队列
    Spring 详解(三)------- SpringMVC拦截器使用
    slf4j 搭配 log4j2 处理日志
    Spring 详解(二)------- AOP关键概念以及两种实现方式
    Spring 详解(一)------- AOP前序
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12366237.html
Copyright © 2011-2022 走看看