自定义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);
        }
    }

}

你可能感兴趣的:(自定义ListView下拉刷新和上拉加载)