ListView使用技巧

设置ListView需要显示在第几页

当需要指定ListView具体显示的Item时,可以通过如下代码来实现:

mListView.setSelection(position);

但这个方法类似scrollTo,是瞬间完成的移动。除此之外,还可以使用如下代码来实现平滑移动。

mListView.smoothScrollToPosition(position);
mListView.smoothScrollByOffset(offset);
mListView.smoothScrollBy(distance, duration);

ListView滑动监听

ListView的滑动监听,是ListView中最重要的技巧,很多重写的ListView,基本上都是在滑动事件的处理上下功夫,通过判断滑动事件进行不同的逻辑处理。而为了更加精确地监听滑动事件,开发者通常还需要使用GestureDetector手势识别、VelocityTracker滑动速度检测等辅助类来完成更好的监听。一般有两种监听方式,一种是通过OnTouchListener来实现监听,另一种是使用OnScrollListener来实现监听。

OnTouchListener

通过ACTION_DOWN、ACTION_MOVE、ACTION_UP这三个事件发生时的坐标,就可以根据坐标判断用户滑动的方向,并在不同的事件中进行相应的逻辑处理,代码如下:

        mListView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            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;
            }
        });

OnScrollListener

OnScrollListener是AbsListView中的监听事件,它封装了很多与ListView相关的信息,使用也更加灵活。

        mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            private int lastVisibleItemPosition;//上次第一个可视的Item的ID

            /**
             * 当用户没有做手指抛动的状态时,这个方法只会回调2次,否则会回调3次,差别就是手指抛动的这个状态。
             * 通常情况下,我们会在这个方法中通过不同的状态来设置一些标志Flag,来区分不同的滑动状态,供其它
             * 方法处理。
             * @param view
             * @param scrollState
             */
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                switch (scrollState) {
                    case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                        //滑动停止时
                        Log.d("Test", "SCROLL_STATE_IDLE");
                        break;
                    case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                        //正在滚动
                        Log.d("Test", "SCROLL_STATE_TOUCH_SCROLL");
                        break;
                    case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                        //手指抛动时,即手指用力滑动,在离开后ListView由于惯性继续滑动的状态
                        Log.d("Test", "SCROLL_STATE_FLING");
                        break;
                }
            }

            /**
             * 该方法在ListView滚动时会一直回调,通过该方法的后3个参数,可以很方便地进行一些判断
             * @param view
             * @param firstVisibleItem 当前能看见的第一个Item的ID(从0开始)
             * @param visibleItemCount 当前看见的Item总数(包括没有显示完整的Item)
             * @param totalItemCount 整个ListView的Item总数
             */
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                //滚动时一直调用
                Log.d("Test", "onScroll");

                //判断是否滚动到最后一行
                if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {

                }

                //判断滚动的方向
                if (firstVisibleItem > lastVisibleItemPosition) {
                    //上滑
                } else if (firstVisibleItem < lastVisibleItemPosition) {
                    //下滑
                }
                lastVisibleItemPosition = firstVisibleItem;
            }
        });

另外,ListView也给我们提供了一些封装的方法来获得当前可视的Item的位置信息:

        //获取可视区域内最后一个Item的id
        mListView.getLastVisiblePosition();
        //获取可视区域内第一个Item的id
        mListView.getFirstVisiblePosition();

具有弹性的ListView

在IOS系统中,列表都是具有弹性的,即滚动到底端或者顶端后会继续往下或者往上滑动一段距离。网上有很多通过重写ListView来实现弹性效果的方法,比如增加HeadView或者使用ScrollView进行嵌套,方法很多,不过可以使用一种非常简单的方法来实现这个效果。虽然不如那些方法可定制化高、效果丰富,但主要的目的是让我们学会如何从源代码中找到问题的解决方法,效果图如下。

我们在查看ListView的源代码时可以发现,ListView中有一个控制滑动到边缘的处理方法,如下所示:

protected boolean overScrollBy(int deltaX, int deltaY,
            int scrollX, int scrollY,
            int scrollRangeX, int scrollRangeY,
            int maxOverScrollX, int maxOverScrollY,
            boolean isTouchEvent)

注意参数:maxOverScrollY,注释中写道——Number of pixels to overscroll by in either direction along the Y axis。由此可以发现,虽然它的默认值是0,但其实只要修改这个参数的值,就可以让ListView具有弹性了。代码如下:

package com.example.huangfei.myapplication;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.ListView;

/**
 * Created by huangfeihong on 2016/5/4.
 * 具有弹性的ListView
 */
public class FlexibleListView extends ListView {

    private int mMaxOverDistance = 50;
    private Context mContext;

    public FlexibleListView(Context context) {
        super(context);
        mContext = context;
        init();
    }

    public FlexibleListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

    public FlexibleListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init();
    }

    //让不同分辨率设备的弹性距离基本一致
    private void init() {
        DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
        float density = metrics.density;
        mMaxOverDistance = (int) (density * mMaxOverDistance);
    }

    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxOverDistance, isTouchEvent);
    }
}

自动显示、隐藏布局的ListView

若要实现当我们在ListView上滑动的时候,顶部的布局就会相应的隐藏或显示的效果,我们应该怎么办,效果图如下:

要让一个布局显示或者隐藏并带有动画效果,可以通过属性动画来很方便地实现,所以这个效果的关键在于根据ListView的滑动方向来判断是否需要显示或隐藏对应的布局。

布局文件如下:

<?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:orientation="vertical">

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

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@android:color/holo_blue_light"/>
</RelativeLayout>

代码如下:

package com.example.huangfei.myapplication;

import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/**
 * 自动显示、隐藏布局的ListView
 */
public class ScrollHideListViewActivity extends Activity {

    private ListView mListView;
    private Toolbar mToolbar;

    private String[] data = new String[30];

    private float mFirstY;
    private float mCurrentY;
    private int mDirection;
    private int mTouchSlop;
    private boolean mShow = true;

    private ObjectAnimator mAnimator;

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

        mListView = (ListView) findViewById(R.id.listview);
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        for (int i = 0; i < data.length; i++) {
            data[i] = "Item " + i;
        }

        /**
         * 在开使判断滑动事件之前,要先给ListView增加一个HeaderView,避免第一个Item被Toolbar遮挡.
         * 其中通过使用abc_action_bar_default_height_material属性获取系统Actionbar的高度
         */
        View headerView = new View(this);
        headerView.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, (int) getResources().getDimension(R.dimen.abc_action_bar_default_height_material)));
        mListView.addHeaderView(headerView);

        mListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, data));

        //定义系统认为的最低滑动距离
        mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
        ObjectAnimator mAnimator;
        mListView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN://触摸时操作
                        mFirstY = event.getY();
                        break;
                    case MotionEvent.ACTION_MOVE://移动时操作
                        mCurrentY = event.getY();
                        if (mCurrentY - mFirstY > mTouchSlop) {
                            mDirection = 0;//down
                        } else if (mFirstY - mCurrentY > mTouchSlop) {
                            mDirection = 1;//up
                        }

                        if (mDirection == 1) {
                            if (mShow) {
                                toolbarAnim(1);//hide
                                mShow = !mShow;
                            }
                        } else if (mDirection == 0) {
                            if (!mShow) {
                                toolbarAnim(0);//show
                                mShow = !mShow;
                            }
                        }
                        break;
                    case MotionEvent.ACTION_UP://离开时操作
                        break;
                }
                return false;
            }
        });
    }

    private void toolbarAnim(int flag) {
//        if (mAnimator != null && mAnimator.isRunning()) {
//            mAnimator.cancel();
//        }
        if (flag == 0) {
            mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(), 0);
        } else {
            mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(), -mToolbar.getHeight());
        }
        mAnimator.start();
    }
}

这里使用了Toolbar这样一个新控件,Google已经推荐它用来逐渐取代ActionBar了,因为它更灵活。但是在使用的时候,一定要注意使用的theme一定要是NoActionBar的,不然会引起冲突。

代码地址

时间: 2024-10-11 12:59:47

ListView使用技巧的相关文章

第二章 控件架构与自定义控件详解 + ListView使用技巧 + Scroll分析

1.Android控件架构下图是UI界面架构图,每个Activity都有一个Window对象,通常是由PhoneWindow类来实现的.PhoneWindow将DecorView作为整个应用窗口的根View,DecorView将屏幕分成两部分:TitleView和ContentView.ContentView实际上是一个FrameLayout,里面容纳的就是我们在xml布局文件中定义的布局. 为什么调用requestWindowFeature()方法一定要在setContentView()方法调

Android群英传笔记——第四章:ListView使用技巧

Android群英传笔记--第四章:ListView使用技巧 近期也是比較迷茫.可是有一点点还是要坚持的,就是学习了.近期离职了,今天也是继续温习第四章ListView,也拖了事实上也挺久的了,listview可谓是老牌大将了,非常多的应用场景都要使用它,他也是我们用得最多的控件之中的一个了,尽管如今出来了一个RecyclerView,可是ListView的地位一时半会儿还是撼动不了的.这就促使我们更加应该去把他掌握了 一.Listview经常使用优化技巧 我们一步步来把ListView学习好

Android之ListView常用技巧

ListView是一个非常常用的列表控件,虽然在5.x时代ListView的风头正在逐渐的被RecyclerView抢去,但是ListView的使用范围依然十分广泛. 接下来的ListView的常用技巧是在平时的开发和学习中了解到的,如有雷同,纯属我抄! 技巧1:设置项目间分隔线 技巧2:隐藏滚动条 技巧3:设置第一个可视条目是第几项 技巧4:添加/取消item的点击效果. 技巧5:处理数据项为空的时候的ListView 技巧6:动态更新ListView 下面依次介绍 1.设置项目间的分割线 这

AndroidUI组件之ListView小技巧

android:fadingEdge="none"//出去黑影 android:listSelector="@android:color/transparent"//去除Item点击效果 android:scrollbars="none"//去除滚动条 android:cacheColorHint="#00000000" //背景色透明 android:divider="@null"//无分隔条 如果在一个

ListView 小技巧

1.如何取消Listview的滚动条? setVerticalScrollBarEnabled(false) 2.白色的背景,ListView滚屏进行中的时候,背景会变成黑色,解决办法? android:cacheColorHint="#00000000" 3.ListView滚动条怎么一直都显示? android:fadeScrollbars="false" 4.ListView隔行变色: int[] colors={Color.BLUE,Color.CYAN};

Andorid ListView使用技巧

一.使用ViewHolder模式提高效率 ViewHolder模式充分利用ListView的视图缓存机制,避免了每次在调用getView()方法的时候都去通过findViewById()方法实例化控件.使用ViewHolder模式,需要在自定义Adapter中定义一个内部类ViewHolder,并将布局中的控件作为成员变量.起始时,ListView创建的Cell条数量是当前屏幕显示的Cell条数,在向上滚动时,新显示的Cell是滚出屏幕的Cell的复用.与iOS的TableView的Cell优化

【幻化万千戏红尘】qianfeng-Android-Day08-基础学习:ListView

ListView 一.ListView介绍: (一). ListView 概念: ListView是Android中最重要的组件之一,几乎每个Android应用中都会使用ListView.它以垂直列表的方式列出所需的列表项. java.lang.Object ? android.view.View ? android.view.ViewGroup ? android.widget.AdapterView<T extends android.widget.Adapter> ? android.w

C# WinForm开发系列 - ListBox/ListView/Panel

转自会飞的小猪文章 C# WinForm开发系列 - ListBox/ListView/Panel 在博客园看到了一篇博文,觉得很不错,就转载过来了. 包含自定义绘制的ListBox, 带拖动,图片显示, 内嵌其它控件, 打印等扩展功能的ListView(文章及相关代码搜集自网络,仅供学习参考,版权属于原作者! ). 1.ColorListBox   ColorListBox.zip 2.RadioListBox   RadioListBox.rar 3.扩展CheckedListBox控件  

Android 彻底征服 ListView 一 (实用篇)

ListView使用技巧 对于Android开发,相信ListView这个控件大家一定不会陌生,它的重要性不言而喻,它的功能纷繁复杂,在项目中的表现形式灵活多变,要想得心应手的使用不并容易,今天带领大家一起领略ListView的风采. 1.使用ViewHolder @Override public View getView(int i, View view, ViewGroup viewGroup) { ViewHolder holder; if(view==null){ holder=new