让Android Support V4中的SwipeRefreshLayout支持上拉加载更多

               

前言

 原来的Android SDK中并没有下拉刷新组件,但是这个组件确实绝大多数APP必备的一个部件。好在google在v4包中出了一个SwipeRefreshLayout,但是这个组件只支持下拉刷新,不支持上拉加载更多的操作。因此,我们就来简单的扩展一下这个组件以实现上拉下载的目的。

基本原理

 上拉加载或者说滚动到底部时自动加载,都是通过判断是否滚动到了ListView或者其他View的底部,然后触发相应的操作,这里我们以ListView来说明。因此我们需要在监听ListView的滚动事件,当ListView滚动到底部时自动触发加载操作;但是当用户支持手指滑动屏幕,没有滚动时,我们也需要让它加载,因此这种情形就是上拉加载更多。所以我们需要在触摸事件里面进行判断,如果到了底部,且用户是上拉操作,那么执行加载更多。更多关于下拉刷新、上拉加载请参考打造通用的Android下拉刷新组件(适用于ListView、GridView等各类View)
 时间有限,直接上代码吧。

实现代码

/** * 继承自SwipeRefreshLayout,从而实现滑动到底部时上拉加载更多的功能. *  * @author mrsimple */public class RefreshLayout extends SwipeRefreshLayout implements OnScrollListener {    /**     * 滑动到最下面时的上拉操作     */    private int mTouchSlop;    /**     * listview实例     */    private ListView mListView;    /**     * 上拉监听器, 到了最底部的上拉加载操作     */    private OnLoadListener mOnLoadListener;    /**     * ListView的加载中footer     */    private View mListViewFooter;    /**     * 按下时的y坐标     */    private int mYDown;    /**     * 抬起时的y坐标, 与mYDown一起用于滑动到底部时判断是上拉还是下拉     */    private int mLastY;    /**     * 是否在加载中 ( 上拉加载更多 )     */    private boolean isLoading = false;    /**     * @param context     */    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;                // 设置滚动监听器给ListView, 使得滚动的情况下也可以自动加载                mListView.setOnScrollListener(this);                Log.d(VIEW_LOG_TAG, "### 找到listview");            }        }    }    /*     * (non-Javadoc)     * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)     */    @Override    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 (canLoad()) {                    loadData();                }                break;            default:                break;        }        return super.dispatchTouchEvent(event);    }    /**     * 是否可以加载更多, 条件是到了最底部, listview不在加载中, 且为上拉操作.     *      * @return     */    private boolean canLoad() {        return isBottom() && !isLoading && isPullUp();    }    /**     * 判断是否到了最底部     */    private boolean isBottom() {        if (mListView != null && mListView.getAdapter() != null) {            return mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);        }        return false;    }    /**     * 是否是上拉操作     *      * @return     */    private boolean isPullUp() {        return (mYDown - mLastY) >= mTouchSlop;    }    /**     * 如果到了最底部,而且是上拉操作.那么执行onLoad方法     */    private void loadData() {        if (mOnLoadListener != null) {            // 设置状态            setLoading(true);            //            mOnLoadListener.onLoad();        }    }    /**     * @param loading     */    public void setLoading(boolean loading) {        isLoading = loading;        if (isLoading) {            mListView.addFooterView(mListViewFooter);        } else {            mListView.removeFooterView(mListViewFooter);            mYDown = 0;            mLastY = 0;        }    }    /**     * @param loadListener     */    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 (canLoad()) {            loadData();        }    }    /**     * 加载更多的监听器     *      * @author mrsimple     */    public static interface OnLoadListener {        public void onLoad();    }}

 listview_footer.xml:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:background="@color/umeng_comm_comments_bg"    android:gravity="center"    android:paddingBottom="8dip"    android:paddingTop="5dip" >    <ProgressBar        android:id="@+id/pull_to_refresh_load_progress"        style="@android:style/Widget.ProgressBar.Small.Inverse"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerVertical="true"        android:layout_centerHorizontal="true"        android:paddingRight="100dp"        android:indeterminate="true" />    <TextView        android:id="@+id/pull_to_refresh_loadmore_text"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:gravity="center"        android:paddingTop="5dip"        android:text="@string/load"        android:textAppearance="?android:attr/textAppearanceMedium"        android:textColor="@android:color/darker_gray"        android:textSize="14sp"        android:textStyle="bold" /></RelativeLayout>

使用示例

 refresh.xml布局文件:
<?xml version="1.0" encoding="utf-8"?><myview.RefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/swipe_layout"    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" >    </ListView></myview.RefreshLayout>

 activity中的使用 : 
/** * @author mrsimple */public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);          setContentView(R.layout.refresh);        // 模拟一些数据        final List<String> datas = new ArrayList<String>();        for (int i = 0; i < 20; i++) {            datas.add("item - " + i);        }        // 构造适配器        final BaseAdapter adapter = new ArrayAdapter<String>(this,                android.R.layout.simple_list_item_1,                datas);        // 获取listview实例        ListView listView = (ListView) findViewById(R.id.listview);        listView.setAdapter(adapter);        // 获取RefreshLayout实例        final RefreshLayout myRefreshListView = (RefreshLayout)                findViewById(R.id.swipe_layout);        // 设置下拉刷新时的颜色值,颜色值需要定义在xml中        myRefreshListView                .setColorScheme(R.color.umeng_comm_text_topic_light_color,                        R.color.umeng_comm_yellow, R.color.umeng_comm_green,                        R.color.umeng_comm_linked_text);        // 设置下拉刷新监听器        myRefreshListView.setOnRefreshListener(new OnRefreshListener() {            @Override            public void onRefresh() {                Toast.makeText(MainActivity.this, "refresh", Toast.LENGTH_SHORT).show();                myRefreshListView.postDelayed(new Runnable() {                    @Override                    public void run() {                        // 更新数据                        datas.add(new Date().toGMTString());                        adapter.notifyDataSetChanged();                        // 更新完后调用该方法结束刷新                        myRefreshListView.setRefreshing(false);                    }                }, 1000);            }        });        // 加载监听器        myRefreshListView.setOnLoadListener(new OnLoadListener() {            @Override            public void onLoad() {                Toast.makeText(MainActivity.this, "load", Toast.LENGTH_SHORT).show();                myRefreshListView.postDelayed(new Runnable() {                    @Override                    public void run() {                        datas.add(new Date().toGMTString());                        adapter.notifyDataSetChanged();                        // 加载完后调用该方法                        myRefreshListView.setLoading(false);                    }                }, 1500);            }        });    }    }

效果图

 




 github链接 : 下拉刷新库
 示例在android_my_pull_demo工程中,进入demo后点击最后一个按钮查看效果即可。注意,在刷新和加载时,需要有一定的延时才能看到效果,这里我们用postDelay来模拟网络请求等延时操作,否则将看不到加载效果。这里只提供一个实现思路,代码不太完善,需要用的请自行完善并测试。
 

 注意
 如果出现 HeaderViewListAdapter 转换异常,那么请使用 RefreshLvLayout中的setAdapter 函数为ListView设置Adapter,
这样可以确保在设置Adapter之前已经添加了Footer。

           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值