SwipeRefreshLayout的上拉加载实现方法

作者: StChris | 来源:发表于2017-01-13 17:10 被阅读264次

    SwipeRefreshLayout 是 Google官方提出的下拉刷新控件,官方功能只支持下拉刷新。SwipeRefreshLayout的上拉加载实现有两种方法,一种是实现滑动监听,当滑动到底部时实现加载更多功能;一种是通过事件传递机制监听上拉动作,然后实现加载更多功能。

    1.第一种加载原理:

    //继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能.
    public class RefreshLayout extends SwipeRefreshLayout implements    OnScrollListener {
    // listview实例
    private ListView mListView;
    // 上拉接口监听器, 到了最底部的上拉加载操作
    private OnLoadListener mOnLoadListener;
    // ListView的加载中footer
    private View mListViewFooter;
    // 是否在加载中 ( 上拉加载更多 )
    private boolean isLoading = false;
    
    public RefreshLayout(Context context) {
        this(context, null);
    }
    
    public RefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        //一个圆形进度条
        mListViewFooter = LayoutInflater.from(context).inflate(
                R.layout.listview_footer, null, false);
    }
    
    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // 初始化ListView对象
        if (mListView == null) {
            getListView();
        }
    }
    
    // 获取ListView对象
    private void getListView() {
        int childs = getChildCount();
        if (childs > 0) {
            View childView = getChildAt(0);
            if (childView instanceof ListView) {
                mListView = (ListView) childView;
                // 设置滚动监听器给ListView
                mListView.setOnScrollListener(this);
            }
        }
    }
    
    
    
    // 设置加载状态,添加或者移除加载更多圆形进度条
    public void setLoading(boolean loading) {
        isLoading = loading;
        if (isLoading) {
            mListView.addFooterView(mListViewFooter);
        } else {
            mListView.removeFooterView(mListViewFooter);
    
        }
    }
    
    //设置监听器
    public void setOnLoadListener(OnLoadListener loadListener) {
        mOnLoadListener = loadListener;
    }
    
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    
    }
    
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
    
        // 判断是否到了最底部,并且不是在加载数据的状态
        if (mListView.getLastVisiblePosition() == mListView.getAdapter()
                .getCount() - 1 && isLoading == false) {
            // 首先设置加载状态
            setLoading(true);
            // 调用加载数据的方法
            mOnLoadListener.onLoad();
    
        }
    
    }
    
    // 加载更多的接口
    public interface OnLoadListener {
        public void onLoad();
    }
    }
    

    注释写的很清楚,实现滑动监听,然后初始化listview,写好加载任务接口与方法。在滑动监听方法里面,有几个参数注意一下:
    firstVisibleItem 表示在当前屏幕显示的第一个listItem在整个listView里面的位置(下标从0开始)
    visibleItemCount表示在现时屏幕可以见到的ListItem(部分显示的ListItem也算)总数
    totalItemCount表示ListView的ListItem总数
    listView.getLastVisiblePosition()表示在现时屏幕最后一个ListItem (最后ListItem要完全显示出来才算)在整个ListView的位置(下标从0开始)
    刚开始只判断是否滑动到了最底部,没有对加载状态进行判断,导致程序运行崩溃,在最底部加载数据时会一直加载。后来加上判断,默认不加载数据,isLoading==false,滑动到最底部加载数据时,设置为true,当加载完成以后,设置为false,加载完毕。

    2.第二种加载原理:

    public class RefreshLayout extends SwipeRefreshLayout {
     // listview实例
    private ListView mListView;
    // 上拉接口监听器, 到了最底部的上拉加载操作
    private OnLoadListener mOnLoadListener;
    // ListView的加载中footer
    private View mListViewFooter;
    // 是否在加载中 ( 上拉加载更多 )
    private boolean isLoading = false;
    
    // 按下时的y坐标
    private int mYDown;
    // 抬起时的y坐标
    private int mLastY;
    // 滑动到最下面时的上拉操作
    private int mTouchSlop;
    
    public RefreshLayout(Context context) {
        this(context, null);
    }
    
    public RefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mListViewFooter = LayoutInflater.from(context).inflate(
                R.layout.listview_footer, null, false);
    }
    
    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // 初始化ListView对象
        if (mListView == null) {
            getListView();
        }
    }
    
    // 获取ListView对象
    private void getListView() {
        int childs = getChildCount();
        if (childs > 0) {
            View childView = getChildAt(0);
            if (childView instanceof ListView) {
                mListView = (ListView) childView;
            }
        }
    }
    
    public boolean dispatchTouchEvent(MotionEvent event) {
        final int action = event.getAction();
    
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            // 按下
            mYDown = (int) event.getRawY();
            break;
    
        case MotionEvent.ACTION_MOVE:
            // 移动
            mLastY = (int) event.getRawY();
            break;
    
        case MotionEvent.ACTION_UP:
            // 抬起
            if ((mYDown - mLastY) >= mTouchSlop && isLoading == false) {
                // 设置状态
                setLoading(true);
                //
                mOnLoadListener.onLoad();
            }
            break;
        default:
            break;
        }
    
        return super.dispatchTouchEvent(event);
    }
    
    // 设置加载状态
    public void setLoading(boolean loading) {
        isLoading = loading;
        if (isLoading) {
            mListView.addFooterView(mListViewFooter);
        } else {
            mListView.removeFooterView(mListViewFooter);
    
        }
    }
    
    // 设置监听器
    public void setOnLoadListener(OnLoadListener loadListener) {
        mOnLoadListener = loadListener;
    }
    
    // 加载更多的接口
    public interface OnLoadListener {
        public void onLoad();
    }
    }
    

    初始化数据都一样,不同的是记录了两个Y坐标,一个按下,一个抬起,用来判断滑动到底部时的上拉动作。getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件,如viewpager就是用这个距离来判断用户是否翻页。
    然后就是通过事件传递机制,拿到view的三个动作:
    MotionEvent.ACTION_DOWN 按下View,是所有事件的开始
    MotionEvent.ACTION_MOVE 滑动事件
    MotionEvent.ACTION_UP 与down对应,表示抬起
    当滑动的距离大于或者等于要求距离并且加载状态为false时,开始设置状态,加载数据,原理和上面一样。

    相关文章

      网友评论

        本文标题:SwipeRefreshLayout的上拉加载实现方法

        本文链接:https://www.haomeiwen.com/subject/deusbttx.html