自定义ListView下拉刷新和上拉加载

为何写这个文章

  • 总结一下知识点,更好的巩固一下。
  • 现在有好多第三方的下拉刷新和上拉加载更多的控件,比如MaterialRefreshLayout + RecycleView 还有PullToRefresh,可以很方便的帮助我们实现下拉和上拉。
  • 原理应该都差不多。那么今天就来看下自定义的ListView的下拉刷新和上拉加载更多的实现
一、首先看下下拉刷新效果

这里写图片描述
分析:

解析上图:

  • 一、下拉刷新的时候 箭头朝下(刚刚拉出来)
  • 二、下拉到一定程度 箭头朝上 文字改为松开刷新
  • 三、松开之后 箭头消失,出现一个圆形加载progressBar 文字改为正在刷新(图片这个显示不太明显)
  • 四、当然这个最后刷新的时间,就是获取当前系统时间,赋值即可

好了,既然知道了这图形的意思,那么我们就来自定义我们的listview吧。

首先先解释一下怎么实现,我们在listview加入了头部(HeaderView)用来刷新提示,加入了尾部(用来加载更多的提示),当然在没有产生这两个动作之前,这两个是要隐藏的,只有我们做了相应的动作之后才会有显示的。

第一步 创建RefreshListView
public class RefreshListView extends ListView {

    //重写构造方法
    public RefreshListView(Context context) {
        //在这里我们用到了this这个关键字,这样一层调一层,不用每个构造方法中都去调用我们的初始化方法了
        this(context, null);
    }

    public RefreshListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initHeaderView();
        initFooterView();
    }
}
第二步初始化布局控件

在这里我们先看下布局吧

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

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="20dp">

        <ImageView
            android:id="@id/ivImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@mipmap/common_listview_headview_red_arrow"/>

        <ProgressBar
            android:visibility="invisible"
            android:id="@+id/progressBar"
<!--在这里我们自定义了ProgressBar的样式,系统自带的不太好看-->            android:indeterminateDrawable="@drawable/custom_progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>

    </FrameLayout>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@id/tvTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下拉刷新"
            android:textColor="@color/red_lovenews"
            android:textSize="24dp"/>

        <TextView
            android:id="@id/tvData"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="3dp"
            android:text="最后刷新时间:2016-01-17 14:54:07"
            android:textSize="18dp"/>
    </LinearLayout>
</LinearLayout>

自定义的ProgressBar的样式

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360">
    <shape
        android:innerRadius="15dp"
        android:shape="ring"
        android:thickness="5dp"
        android:useLevel="false">
        <gradient
            android:centerColor="#3F00"
            android:endColor="#F00"
            android:startColor="#FFF"/>
    </shape>
</rotate>

在RefreshListView中初始化布局控件

  /**
     * 初始化布局控件
     */
    private void initViews() {
        tvData = (TextView) mHeaderView.findViewById(R.id.tvData);
        tvData.setText("最后刷新时间:" + getCurrentTime());
        tvTitle = (TextView) mHeaderView.findViewById(R.id.tvTitle);
        progressBar = (ProgressBar) mHeaderView.findViewById(R.id.progressBar);
        ivImage = (ImageView) mHeaderView.findViewById(R.id.ivImage);

    }
第三步 加入头布局
 /**
     * 初始化头布局
     */
    private void initHeaderView() {
        mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);

        this.addHeaderView(mHeaderView);

        initViews();

        initAnimation();
        //测量布局
        mHeaderView.measure(0, 0);

        //获得HeaderView的高度,这个要在测量(measure)之后才能获取到
        measuredHeight = mHeaderView.getMeasuredHeight();

        //隐藏HeaderView(只有在下拉的时候才去显示)
        mHeaderView.setPadding(0, -measuredHeight, 0, 0);
    }
第四步 实现触摸事件

当然了,既然要下拉刷新,改变布局,就要相应触摸事件了,在这里我们先定义三种STATE状态

/**
     * 下拉刷新
     */
    private static final int STATE_PULL_REFRESH = 0;

    /**
     * 松开刷新
     */
    private static final int STATE_RELEASE_REFRESH = 1;

    /**
     * 正在刷新
     */
    private static final int STATE_REFRESHING = 2;

    /**
     * 当前刷新状态
     */
    private static int CURRENT_STATE = STATE_PULL_REFRESH;

重写onTouchEvent方法
在这里实现逻辑,解释在代码里面,在这里直接上代码:

/**
     * 点击触摸事件
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                /**
                 * 获取到按下的时候的坐标
                 */
                startY = ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (startY == -1) {
                    startY = ev.getRawY();
                }
                /**
                 * 获取到移动的时候的坐标
                 */
                float endY = ev.getRawY();

                /**
                 * 移动偏移量
                 */
                float dy = endY - startY;

                //dy大于0的时候才能出来,并且是第一个元素item显示
                //也就是说,只有当我们下拉的显示的是第一个item(在下拉的时候表示我们要去刷新了)
                //getFirstVisiblePosition()获取到第一个item显示的位置
                if (dy > 0 && getFirstVisiblePosition() == 0) {

                    //得到padding值
                    int padding = (int) (dy - measuredHeight);

                    //设置HeaderView的padding值
                    mHeaderView.setPadding(0, padding, 0, 0);

                    if (padding > 0) {
                        //状态改为松开刷新
                        CURRENT_STATE = STATE_RELEASE_REFRESH;

                    } else if (padding < 0 && CURRENT_STATE != STATE_PULL_REFRESH) {
                    //如果padding<0 ,并且状态不是下拉刷新的时候,我们要设置状态为下拉刷新,因为这个时候达不到执行其他状态的条件(padding>=0)
                        CURRENT_STATE = STATE_PULL_REFRESH;
                    }

                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                //重置
                startY = -1;
                if (CURRENT_STATE == STATE_RELEASE_REFRESH) {
                    CURRENT_STATE = STATE_REFRESHING;
                    //显示
                    mHeaderView.setPadding(0, 0, 0, 0);
                    refreshState();
                } else if (CURRENT_STATE == STATE_PULL_REFRESH) {
                    //隐藏标题
                    //这种情况是没有达到刷新的条件
                    mHeaderView.setPadding(0, -measuredHeight, 0, 0);
                }
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }
第五步 刷新状态显示
/**
     * 根据当前状态改变刷新的时候的显示
     */
    private void refreshState() {
        switch (CURRENT_STATE) {
            case STATE_PULL_REFRESH:
                tvTitle.setText("下拉刷新");
                ivImage.setVisibility(VISIBLE);
                progressBar.setVisibility(INVISIBLE);
                //箭头下拉动画
                ivImage.startAnimation(animDown);
                break;
            case STATE_RELEASE_REFRESH:
                tvTitle.setText("松开刷新");
                ivImage.setVisibility(VISIBLE);
                progressBar.setVisibility(INVISIBLE);
                //箭头上升动画
                ivImage.startAnimation(animUp);
                break;
            case STATE_REFRESHING:
                tvTitle.setText("正在刷新");
                //必须先清除动画,才能隐藏
                ivImage.clearAnimation();
                ivImage.setVisibility(INVISIBLE);
                progressBar.setVisibility(VISIBLE);
                if (mListener != null) {
                    mListener.onRefresh();
                }
                break;
            default:
                break;
        }
    }
第六步 加载图片动画实现
private void initAnimation() {
        /**
         *  箭头向上的动画
         */
        animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f
                , Animation.RELATIVE_TO_SELF, 0.5f);
        animUp.setDuration(200);
        animUp.setFillAfter(true);

        /**
         *    箭头向下的动画
         */
        animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f
                , Animation.RELATIVE_TO_SELF, 0.5f);
        animUp.setDuration(200);
        animUp.setFillAfter(true);
    }

获取系统时间

 /**
     * 获得系统当前的时间
     * @return
     */
    public String getCurrentTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String currentTime = sdf.format(new Date());
        return currentTime;
    }

既然下拉已经写好了,这个时候我们就要对外界提供调用的接口了,要不然外界怎么去调用我们写的呢。

 OnRefreshListener mListener;

    public void setOnRefreshListener(OnRefreshListener listener) {
        mListener = listener;
    }


    /**
     * 下拉刷新和上拉加载更多接口
     */
    public interface OnRefreshListener {
        //刷新
        void onRefresh();
        //加载更多
        void onLoadMore();
    }

好了,下拉逻辑基本完成,下面我们看下上拉加载更多逻辑

第一步 加入尾布局
/**
     * 初始化FooterView
     */
    private void initFooterView() {
        //加载FooterView布局
        mFooterView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);
        //添加
        this.addFooterView(mFooterView);
        //测量mFooterView
        mFooterView.measure(0, 0);
        //获取到mFooterView的高度
        mFotterViewHeight = mFooterView.getMeasuredHeight();
        //隐藏mFooterView
        mFooterView.setPadding(0, -mFotterViewHeight, 0, 0);

        //设置滑动监听事件
        this.setOnScrollListener(this);
    }
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="horizontal" >

    <ProgressBar
        android:id="@+id/pb_pull_list_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:indeterminateDrawable="@drawable/custom_progress" />

    <TextView
        android:id="@+id/tv_pull_list_header_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="加载中..."
        android:textColor="#ff0000"
        android:textSize="18sp" />
</LinearLayout>
第二步 实现滑动AbsListView.OnScrollListener
 @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        /**
         * SCROLL_STATE_IDLE   滑动停止
         * SCROLL_STATE_FLING  滑动完成
         * 在停止滑动并且滑动停止的时候判断
         */
        if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
            //判断是否显示的是最后一个item,并且是否是加载更多的事件
            if (getLastVisiblePosition() == getCount() -1&& !isLoadingMore) {
                //滑动到最后
                //Log.d("RefreshListView", "滑动到底了");
                //显示mFooterView
                mFooterView.setPadding(0,0,0,0);
                //改变listview显示的位置
                setSelection(getCount());
                //加载更多设置为true
                isLoadingMore = true;
                if (mListener != null){
                    //调用接口  加载更多的接口
                    mListener.onLoadMore();
                }
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

在这下面我们对头和尾进行处理,当加载是否完成,我们都要去隐藏头尾布局,恢复设置

    /**
     * 加载完成   要隐藏我们的头布局和尾布局
     *
     * @param success
     */
    public void OnRefreshComplete(boolean success) {

        if (isLoadingMore){
            //隐藏
            mFooterView.setPadding(0,-mFotterViewHeight,0,0);
            //加载更多设置为false
            isLoadingMore = false;
        } else {
            //
            CURRENT_STATE = STATE_PULL_REFRESH;
            tvTitle.setText("下拉刷新");
            ivImage.setVisibility(VISIBLE);
            progressBar.setVisibility(INVISIBLE);

            mHeaderView.setPadding(0, -measuredHeight, 0, 0);

            if (success) {
                tvData.setText("最后刷新时间:" + getCurrentTime());
            }
        }
    }

基本上拉加载更多和下拉刷新初步完成,当然了,这个只是动画,和上拉下拉响应,完成加载和刷新还是得在你获取数据的时候处理,也就是说,我们可以给listview设置,比如:


        /**
         * 设置下拉刷新的事件监听
         */
        mListView.setOnRefreshListener(new RefreshListView.OnRefreshListener() {

            /**
             * 下拉刷新
             */
            @Override
            public void onRefresh() {
            //这个就是下拉刷新,重新获取服务器数据即可
                getDataFromServer();
            }

            /**
             * 上拉加载更多
             */
            @Override
            public void onLoadMore() {
                if (mMoreUrl != null) {
                //这个就是获取下一页数据(加载更多)
                    getMoreDataFromServer();
                } else {
                    Toast.makeText(mActivity, "已经是最后一页了", Toast.LENGTH_SHORT).show();
                    mListView.OnRefreshComplete(false);  //收起脚部局
                }
            }
        });

接下来,在来优化一下,存在的一个毛病,或者我们优化一下会更好,就是我们加入了头布局,这样,我们在对listview设置触摸监听事件的时候,由于加入了头布局,那我们在 点击获取 item的position的时候,会获取到的和我们想要的是不一样的额,这是因为我们的头布局加入了,就会把我们的listview的条目增加,然后获取到的position也会增加,好了,我们来稍微改一下代码,实现点击还是获取到我们想要的效果。

 @Override
    public void setOnItemClickListener(OnItemClickListener listener) {

        /**
         * 把当前的mItemClickListener传递到底层,重写
         */
        super.setOnItemClickListener(this);
        mItemClickListener = listener;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if (mItemClickListener !=null){
            //减去两个头布局getHeaderViewsCount()
            //getHeaderViewsCount()获取到头布局的个数
            //在这里我们对onItemClick中的position直接减去我们的headerview
            //然后我们在重写这个setOnItemClickListener(),方法,把我们这个修改过的事件监听传给当前,然后我们在我们的代码中使用的时候,就去重写我们修改过后的setOnItemClickListener()这个方法
            mItemClickListener.onItemClick(parent,view,position - getHeaderViewsCount(),id);
        }
    }

好了,到此,自定义的ListView下拉刷新和上拉加载已经全部完成了,逻辑就那么多,希望有帮助,也是我的总结。

接下来看下完整代码:

package com.example.lovenews.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.lovenews.R;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by 若兰 on 2016/1/17.
 * 一个懂得了编程乐趣的小白,希望自己
 * 能够在这个道路上走的很远,也希望自己学习到的
 * 知识可以帮助更多的人,分享就是学习的一种乐趣
 * QQ:1069584784
 * csdn:http://blog.csdn.net/wuyinlei
 */

public class RefreshListView extends ListView implements AbsListView.OnScrollListener, AdapterView.OnItemClickListener {

    /**
     * 下拉刷新
     */
    private static final int STATE_PULL_REFRESH = 0;

    /**
     * 松开刷新
     */
    private static final int STATE_RELEASE_REFRESH = 1;

    /**
     * 正在刷新
     */
    private static final int STATE_REFRESHING = 2;

    /**
     * 当前刷新状态
     */
    private static int CURRENT_STATE = STATE_PULL_REFRESH;

    /**
     * Y轴坐标
     */
    private float startY;

    /**
     * 头布局
     */
    private View mHeaderView;

    /**
     * 尾布局
     */
    private View mFooterView;

    /**
     * 头布局高度
     */
    private int measuredHeight;

    /**
     * 尾布局高度
     */
    private int mFotterViewHeight;

    /**
     * 布局控件
     */
    private ImageView ivImage;
    private ProgressBar progressBar;
    private TextView tvTitle, tvData;

    /**
     * 箭头动画
     */
    private RotateAnimation animUp, animDown;



    public RefreshListView(Context context) {
        this(context, null);
    }

    public RefreshListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initHeaderView();
        initFooterView();
    }

    /**
     * 初始化头布局
     */
    private void initHeaderView() {
        mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);

        this.addHeaderView(mHeaderView);

        initViews();

        initAnimation();
        //测量布局
        mHeaderView.measure(0, 0);

        //获得HeaderView的高度,这个要在测量(measure)之后才能获取到
        measuredHeight = mHeaderView.getMeasuredHeight();

        //隐藏HeaderView
        mHeaderView.setPadding(0, -measuredHeight, 0, 0);
    }

    /**
     * 初始化布局控件
     */
    private void initViews() {
        tvData = (TextView) mHeaderView.findViewById(R.id.tvData);
        tvData.setText("最后刷新时间:" + getCurrentTime());
        tvTitle = (TextView) mHeaderView.findViewById(R.id.tvTitle);
        progressBar = (ProgressBar) mHeaderView.findViewById(R.id.progressBar);
        ivImage = (ImageView) mHeaderView.findViewById(R.id.ivImage);

    }

    /**
     * 点击触摸事件
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                /**
                 * 获取到按下的时候的坐标
                 */
                startY = ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (startY == -1) {
                    startY = ev.getRawY();
                }

                if (CURRENT_STATE == STATE_REFRESHING) {
                    break;//正在刷新的时候,不做处理
                }
                /**
                 * 获取到移动的时候的坐标
                 */
                float endY = ev.getRawY();

                /**
                 * 移动偏移量
                 */
                float dy = endY - startY;

                //dy大于0的时候才能出来,并且是第一个元素item显示
                if (dy > 0 && getFirstVisiblePosition() == 0) {

                    //得到padding值
                    int padding = (int) (dy - measuredHeight);

                    //设置HeaderView的padding值
                    mHeaderView.setPadding(0, padding, 0, 0);

                    if (padding > 0) {
                        //状态改为松开刷新
                        CURRENT_STATE = STATE_RELEASE_REFRESH;
                        refreshState();
                    } else if (padding < 0 && CURRENT_STATE != STATE_PULL_REFRESH) {
                        CURRENT_STATE = STATE_PULL_REFRESH;
                    }

                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                //重置
                startY = -1;
                if (CURRENT_STATE == STATE_RELEASE_REFRESH) {
                    CURRENT_STATE = STATE_REFRESHING;
                    //显示
                    mHeaderView.setPadding(0, 0, 0, 0);
                    refreshState();
                } else if (CURRENT_STATE == STATE_PULL_REFRESH) {
                    //隐藏标题
                    mHeaderView.setPadding(0, -measuredHeight, 0, 0);
                }
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 根据当前状态改变刷新的时候的显示
     */
    private void refreshState() {
        switch (CURRENT_STATE) {
            case STATE_PULL_REFRESH:
                tvTitle.setText("下拉刷新");
                ivImage.setVisibility(VISIBLE);
                progressBar.setVisibility(INVISIBLE);
                ivImage.startAnimation(animDown);
                break;
            case STATE_RELEASE_REFRESH:
                tvTitle.setText("松开刷新");
                ivImage.setVisibility(VISIBLE);
                progressBar.setVisibility(INVISIBLE);
                ivImage.startAnimation(animUp);
                break;
            case STATE_REFRESHING:
                tvTitle.setText("正在刷新");
                //必须先清除动画,才能隐藏
                ivImage.clearAnimation();
                ivImage.setVisibility(INVISIBLE);
                progressBar.setVisibility(VISIBLE);
                if (mListener != null) {
                    mListener.onRefresh();
                }
                break;
            default:
                break;
        }
    }

    private void initAnimation() {
        /**
         *  箭头向上的动画
         */
        animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f
                , Animation.RELATIVE_TO_SELF, 0.5f);
        animUp.setDuration(200);
        animUp.setFillAfter(true);

        /**
         *    箭头向下的动画
         */
        animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f
                , Animation.RELATIVE_TO_SELF, 0.5f);
        animUp.setDuration(200);
        animUp.setFillAfter(true);
    }

    OnRefreshListener mListener;

    public void setOnRefreshListener(OnRefreshListener listener) {
        mListener = listener;
    }


    /**
     * 下拉刷新和上拉加载更多接口
     */
    public interface OnRefreshListener {
        void onRefresh();
        void onLoadMore();
    }

    /**
     * 加载完成   要隐藏我们的头布局和尾布局
     *
     * @param success
     */
    public void OnRefreshComplete(boolean success) {

        if (isLoadingMore){
            //隐藏
            mFooterView.setPadding(0,-mFotterViewHeight,0,0);
            //加载更多设置为false
            isLoadingMore = false;
        } else {
            //
            CURRENT_STATE = STATE_PULL_REFRESH;
            tvTitle.setText("下拉刷新");
            ivImage.setVisibility(VISIBLE);
            progressBar.setVisibility(INVISIBLE);

            mHeaderView.setPadding(0, -measuredHeight, 0, 0);

            if (success) {
                tvData.setText("最后刷新时间:" + getCurrentTime());
            }
        }
    }

    /**
     * 获得系统当前的时间
     * @return
     */
    public String getCurrentTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String currentTime = sdf.format(new Date());
        return currentTime;
    }

    /**
     * 初始化FooterView
     */
    private void initFooterView() {
        //加载FooterView布局
        mFooterView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);
        //添加
        this.addFooterView(mFooterView);
        //测量mFooterView
        mFooterView.measure(0, 0);
        //获取到mFooterView的高度
        mFotterViewHeight = mFooterView.getMeasuredHeight();
        //隐藏mFooterView
        mFooterView.setPadding(0, -mFotterViewHeight, 0, 0);

        //设置滑动监听事件
        this.setOnScrollListener(this);
    }

    /**
     * 是否加载更多
     */
    private boolean isLoadingMore ;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        /**
         * SCROLL_STATE_IDLE   滑动停止
         * SCROLL_STATE_FLING  滑动完成
         * 在停止滑动并且滑动停止的时候判断
         */
        if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
            //判断是否显示的是最后一个item,并且是否是加载更多的事件
            if (getLastVisiblePosition() == getCount() -1&& !isLoadingMore) {
                //滑动到最后
                //Log.d("RefreshListView", "滑动到底了");
                //显示mFooterView
                mFooterView.setPadding(0,0,0,0);
                //改变listview显示的位置
                setSelection(getCount());
                //加载更多设置为true
                isLoadingMore = true;
                if (mListener != null){
                    //调用接口
                    mListener.onLoadMore();
                }
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

    OnItemClickListener mItemClickListener;

    @Override
    public void setOnItemClickListener(OnItemClickListener listener) {

        /**
         * 把当前的mItemClickListener传递到底层,重写
         */
        super.setOnItemClickListener(this);
        mItemClickListener = listener;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if (mItemClickListener !=null){
            //减去两个头布局getHeaderViewsCount()
            mItemClickListener.onItemClick(parent,view,position - getHeaderViewsCount(),id);
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值