Android widget with pull to refresh for all the views,and support loadMore for ListView , RecyclerView, GridView and SwipeRefreshLayout.

Overview

CommonPullToRefresh

Android widget with pull to refresh for all the views,and support loadMore for ListView,RecyclerView,GridView and SwipeRefreshLayout.

android-Ultra-Pull-To-Refresh的基础上增加了加载更多的支持,感谢作者

  • 下拉刷新支持大部分viewListViewScrollViewWebView等,甚至一个单独的TextView
  • 加载更多目前支持ListViewRecyclerViewGridViewSwipeRefreshLayout
  • 支持自定义header以及footer
  • 增加SwipeRefreshLayout刷新方式,同样支持加载更多

Demo APK下载

ListView、RecyclerView截图

GridView截图

SwipeRefreshLayout截图

Usage

Gradle / Android Studio

compile 'com.chanven.lib:cptr:1.1.0'

下拉刷新配置

有6个参数可配置:

  • 阻尼系数

    默认: 1.7f,越大,感觉下拉时越吃力。 mPtrFrame.setResistance(1.7f)

  • 触发刷新时移动的位置比例

    默认,1.2f,移动达到头部高度1.2倍时可触发刷新操作。 mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f)

  • 回弹延时

    默认 200ms,回弹到刷新高度所用时间。 mPtrFrame.setDurationToClose(200)

  • 头部回弹时间

    默认1000msmPtrFrame.setDurationToCloseHeader(1000)

  • 刷新是保持头部

    默认值 truemPtrFrame.setKeepHeaderWhenRefresh(true)

  • 下拉刷新 / 释放刷新

    默认为释放刷新,即falsemPtrFrame.setPullToRefresh(false)

上面是在java代码中配置,也可在xml文件中配置
<?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="match_parent"
    android:orientation="vertical">

    <com.chanven.lib.cptr.PtrClassicFrameLayout
        android:id="@+id/test_list_view_frame"
        xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f0f0f0"
        cube_ptr:ptr_resistance="1.7"
        cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
        cube_ptr:ptr_duration_to_close="200"
        cube_ptr:ptr_duration_to_close_header="1000"
        cube_ptr:ptr_keep_header_when_refresh="true"
        cube_ptr:ptr_pull_to_fresh="false">

        <ListView
            android:id="@+id/test_list_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:choiceMode="singleChoice"
            android:divider="#b0b0b0"
            android:dividerHeight="0.1dp"
            android:fadingEdge="none"
            android:scrollbarStyle="outsideOverlay"/>
    </com.chanven.lib.cptr.PtrClassicFrameLayout>

</LinearLayout>

处理刷新

通过PtrHandler,可以检查确定是否可以下来刷新以及在合适的时间刷新数据。

检查是否可以下拉刷新在PtrDefaultHandler.checkContentCanBePulledDown中有默认简单的实现,你可以根据实际情况完成这个逻辑。

public interface PtrHandler {
    /**
     * 检查是否可以执行下来刷新,比如列表为空或者列表第一项在最上面时。
     * <p/>
     * {@link com.chanven.lib.cptr.PtrDefaultHandler#checkContentCanBePulledDown}
     */
    public boolean checkCanDoRefresh(final PtrFrameLayout frame, final View content, final View header);

    /**
     * 需要加载数据时触发
     *
     * @param frame
     */
    public void onRefreshBegin(final PtrFrameLayout frame);
}

加载更多配置

  • 是否需要加载更多 默认false mPtrFrame.setLoadMoreEnable(true)
  • 是否自动加载 默认true mPtrFrame.setAutoLoadMoreEnable(true)

Header、Footer样式

  • Header 实现接口PtrUIHandler,已有默认实现PtrClassicDefaultHeader,并通过PtrFrameLayout.setHeaderView(View header)设置
  • Footer 实现接口ILoadMoreViewFactory,已有默认实现DefaultLoadMoreViewFooter,并通过PtrFrameLayout.setFooterView(ILoadMoreViewFactory factory)设置

常见问题

  • ViewPager滑动冲突: disableWhenHorizontalMove()
  • 长按LongPressed, setInterceptEventWhileWorking()
  • 如果要禁用下拉刷新,则更改PtrHandler.checkCanDoRefresh的返回实现即可

具体栗子可参考Demo

Comments
  • recyclerview-v7:23.2.1以上,autoMeasure导致的FooterView满屏的问题

    recyclerview-v7:23.2.1以上,autoMeasure导致的FooterView满屏的问题

    最新的recyclerview加了autoMeasure功能,在 RecyclerAdapterWithHF 中的onCreateViewHolder里面, 自己创建的HeaderFooterView不应该在用MATCH_PARENT了.

    FrameLayout frameLayout = new FrameLayout(viewGroup.getContext()); // make sure it fills the space frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); return new HeaderFooterViewHolder(frameLayout);

    opened by Kilnn 4
  • Demo:ListView当footView出现一点就开始加载更多,而RecyclerView需要footView全部出现才可以加载更多?

    Demo:ListView当footView出现一点就开始加载更多,而RecyclerView需要footView全部出现才可以加载更多?

    我在运行Demo的时候发现2个问题:都是上拉加载更多 第一个: 若是ListView,那么当footView出现一点点的时候就会加载更多,而RecyclerView需要footView全部出现才会加载更多。 第二个: mData.add(new String(" RecyclerView item - add " + page)); mAdapter.notifyDataSetChanged(); 必须在一起,如果采用mHandler.sendEmptyMessageDelayed(123, 1500);把加载数据和 mAdapter.notifyDataSetChanged();分开,会有bug。

        ptrClassicFrameLayout.setPtrHandler(new PtrDefaultHandler() {
    
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                     mData.add(new String("  RecyclerView item  - add " + page));
                    mHandler.sendEmptyMessageDelayed(123, 1500);
            }
        });
    
    
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 123) {
                mAdapter.notifyDataSetChanged();
                ptrClassicFrameLayout.loadMoreComplete(true);
                page++;
                Toast.makeText(RecyclerViewActivity.this, "load more complete", Toast.LENGTH_SHORT).show();
            }
        }
    };
    

    会出现bug:一次正常有1.5s的间隔,一次没有(直接是加载更多后的结果),依次循环。

    opened by s1168805219 2
  • 关于添加多点触控问题

    关于添加多点触控问题

    @Chanven 请问下想弄成类似qq那样可以多点连续下拉的问题 我参考其他库的做法在PtrFrameLayout里面添加了下面代码

     @Override
        public boolean dispatchTouchEvent(MotionEvent e) {
            if (!isEnabled() || mContent == null || mHeaderView == null) {
                return dispatchTouchEventSupper(e);
            }
            dealMulTouchEvent(e);
            int action = e.getAction();
            switch (action) {
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    mPtrIndicator.onRelease();
                    if (mPtrIndicator.hasLeftStartPosition()) {
                        if (DEBUG) {
                            PtrCLog.d(LOG_TAG, "call onRelease when user release");
                        }
                        onRelease(false);
                        if (mPtrIndicator.hasMovedAfterPressedDown()) {
                            sendCancelEvent();
                            return true;
                        }
                        return dispatchTouchEventSupper(e);
                    } else {
                        return dispatchTouchEventSupper(e);
                    }
                case MotionEvent.ACTION_DOWN:
                    mHasSendCancelEvent = false;
                    mPtrIndicator.onPressDown(e.getX(), e.getY());
    
                    mScrollChecker.abortIfWorking();
    
                    mPreventForHorizontal = false;
                    // The cancel event will be sent once the position is moved.
                    // So let the event pass to children.
                    // fix #93, #102
                    dispatchTouchEventSupper(e);
                    return true;
    
                case MotionEvent.ACTION_MOVE:
                    mLastMoveEvent = e;
                    final int pointerIndex = MotionEventCompat.findPointerIndex(e, mActivePointerId);
                    final float x = MotionEventCompat.getX(e, pointerIndex);
                    final float y = MotionEventCompat.getY(e, pointerIndex);
                    mPtrIndicator.onMove(x, y);
    //                mPtrIndicator.onMove(e.getX(), e.getY());
                    float offsetX = mPtrIndicator.getOffsetX();
                    float offsetY = mPtrIndicator.getOffsetY();
    
                    if (mDisableWhenHorizontalMove && !mPreventForHorizontal && (Math.abs(offsetX) > mPagingTouchSlop && Math.abs(offsetX) > Math.abs(offsetY))) {
                        if (mPtrIndicator.isInStartPosition()) {
                            mPreventForHorizontal = true;
                        }
                    }
                    if (mPreventForHorizontal) {
                        return dispatchTouchEventSupper(e);
                    }
    
                    boolean moveDown = offsetY > 0;
                    boolean moveUp = !moveDown;
                    boolean canMoveUp = mPtrIndicator.hasLeftStartPosition();
    
                    if (DEBUG) {
                        boolean canMoveDown = mPtrHandler != null && mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView);
                        PtrCLog.v(LOG_TAG, "ACTION_MOVE: offsetY:%s, currentPos: %s, moveUp: %s, canMoveUp: %s, moveDown: %s: canMoveDown: %s", offsetY, mPtrIndicator.getCurrentPosY(), moveUp, canMoveUp, moveDown, canMoveDown);
                    }
    
                    // disable move when header not reach top
                    if (moveDown && mPtrHandler != null && !mPtrHandler.checkCanDoRefresh(this, mContent, mHeaderView)) {
                        return dispatchTouchEventSupper(e);
                    }
    
                    if ((moveUp && canMoveUp) || moveDown) {
                        movePos(offsetY);
                        return true;
                    }
            }
            return dispatchTouchEventSupper(e);
        }
    
        /**
         * http://blog.sina.com.cn/s/blog_8a86f4dd0102whbj.html
         * https://github.com/liaoinstan/SpringView/blob/master/library/src/main/java/com/liaoinstan/springview/widget/SpringView.java
         * 处理多点触控的情况,准确地计算Y坐标和移动距离dy
         * 同时兼容单点触控的情况
         */
        private int mActivePointerId = MotionEvent.INVALID_POINTER_ID;
    
        public void dealMulTouchEvent(MotionEvent ev) {
            final int action = MotionEventCompat.getActionMasked(ev);
            switch (action) {
                case MotionEvent.ACTION_DOWN: {
                    final int pointerIndex = MotionEventCompat.getActionIndex(ev);
                    final float x = MotionEventCompat.getX(ev, pointerIndex);
                    final float y = MotionEventCompat.getY(ev, pointerIndex);
                    mPtrIndicator.onPressDown(x, y);
                    mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
                    break;
                }
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    mActivePointerId = MotionEvent.INVALID_POINTER_ID;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN: {
                    final int pointerIndex = MotionEventCompat.getActionIndex(ev);
                    final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
                    if (pointerId != mActivePointerId) {
                        final float x = MotionEventCompat.getX(ev, pointerIndex);
                        final float y = MotionEventCompat.getY(ev, pointerIndex);
                        mPtrIndicator.onPressDown(x, y);
                        mActivePointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
                    }
                    break;
                }
                case MotionEvent.ACTION_POINTER_UP: {
                    PtrCLog.v(LOG_TAG, "ACTION_POINTER_UP: ");
                    final int pointerIndex = MotionEventCompat.getActionIndex(ev);
                    final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
                    if (pointerId == mActivePointerId) {
                        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                        final float x = MotionEventCompat.getX(ev, pointerIndex);
                        final float y = MotionEventCompat.getY(ev, pointerIndex);
                        mPtrIndicator.onPressDown(x, y);
                        mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
                    }
                    break;
                }
            }
        }
    

    但是当2个在屏幕上面,一个手指滑动然后抬起,会出现位置忽然抖动的情况,请问下这个应该怎么解决呢?

    opened by t2314862168 1
  • Fix broken headings in Markdown files

    Fix broken headings in Markdown files

    GitHub changed the way Markdown headings are parsed, so this change fixes it.

    See bryant1410/readmesfix for more information.

    Tackles bryant1410/readmesfix#1

    opened by bryant1410 0
  • 可以详细说明下 ViewPager滑动冲突的问题吗

    可以详细说明下 ViewPager滑动冲突的问题吗

    在activity的viewpager中使用fragment,fragment中使用了您的CommonPullToRefresh,报 java.lang.NullPointerException: Attempt to invoke virtual method 'void com.chanven.lib.cptr.PtrClassicFrameLayout.disableWhenHorizontalMove(boolean)' on a null object reference 的错误

    opened by magicdra 0
  • 高版本RecyclerView兼容问题

    高版本RecyclerView兼容问题

    使用以下依赖: compile 'com.android.support:appcompat-v7:25.0.0' compile 'com.android.support:recyclerview-v7:25.0.0' compile 'com.android.support:cardview-v7:25.0.0' 进行上拉加载操作,需要将footerview上拉到顶部才开始回调加载方法。

    opened by the-liuchao 2
Owner
null
A generic, customizable, open source Android ListView implementation that has 'Pull to Refresh' functionality.

Android 'Pull to Refresh' ListView library Demo video: http://www.youtube.com/watch?v=VjmdELnm3GI Project A generic, customizable, open source Android

Erik Wallentinsen 639 Nov 17, 2022
This project aims to provide a reusable pull to refresh widget for Android.

Pull To Refresh for Android Note This library is deprecated, a swipe refresh layout is available in the v4 support library. This project aims to provi

Johan Berg 2.5k Jan 2, 2023
HorizontalListView is an Android ListView widget which scrolls in a horizontal manner (in contrast with the SDK-provided ListView which scrolls vertically).

HorizontalListView HorizontalListView is an Android ListView widget which scrolls in a horizontal manner (in contrast with the SDK-provided ListView w

MeetMe 722 Nov 10, 2022
Phoenix Pull-to-Refresh

Phoenix Pull-to-Refresh This project aims to provide a simple and customizable pull to refresh implementation. Made in [Yalantis] (https://yalantis.co

Yalantis 4k Dec 30, 2022
An Android custom ListView and ScrollView with pull to zoom-in.

PullZoomView An Android custom ListView and ScrollView with pull to zoom-in. Features Set ZoomView enable Add HeaderView Custom ZoomView Parallax or N

Frank-Zhu 2.3k Dec 26, 2022
Android library to display a ListView whose cells are not rigid but flabby and react to ListView scroll.

FlabbyListView This library is not maintained anymore and there will be no further releases Android library to display a ListView which cells are not

JPARDOGO 762 Nov 23, 2022
AssignmentListView is an Android ListView widget which calculate image loading times.

AssignmentListView is an Android ListView widget which calculate image loading times.

null 5 Sep 9, 2022
An easy to use Drag & Drop List for Android. Direct replacement of the android ListView.

DragNDropListView DragNDropListView is a direct replacement for the stock Android ListView. If you know how to use ListView, you already know how to u

null 187 Dec 22, 2022
Parallax ScrollView and ListView for Android

Parallax Scrolls Parallax ListView and ScrollView for Android This project includes ScrollView with one or more parallaxed views ListView with paralla

Nir Hartmann 851 Dec 3, 2022
Bringing extended scrolling features to Android's native ListView and ExpandableListView.

About QuickScroll QuickScroll is a library aimed at creating similar scrolling experiences to the native Contacts app's People view. It has the same s

Andras Kindler 461 Nov 11, 2022
Easy to use ListView with pinned sections for Android.

Easy to use ListView with pinned sections for Android 2.1 and higher. Pinned section is a header view which sticks to the top of the list until at lea

Sergej Shafarenka 2.6k Dec 21, 2022
A ListView with pinned section headers for Android

PinnedHeaderListView This library provides a sectioned ListView with pinned headers. It looks and feels much like the default contacts app does on And

James Smith 665 Nov 29, 2022
Awesome Listview filter functionality in Android.

About Awesome Listview filter functionality in Android. See it in Action: https://www.youtube.com/watch?v=RO54U1ES5CA Listview with beautiful transpar

Bhavya  Mehta 446 Nov 20, 2022
Android ListView with sticky headers

DEPRECATED HeaderListView is deprecated. No new development will be taking place. Quickstart Import the HeaderListView module in your Android Studio p

Applidium 314 Nov 10, 2022
Simple ListView based Android AccordionView

Android Accordion View Example git pull import to eclipse properties->android uncheck is library run as android application See main.xml. Screenshot L

Maciej Lopacinski 164 Nov 28, 2022
Android ListView that implements the QuickReturn UI pattern. Written from scratch with focus on performance.

QuickReturn Android ListView that implements the QuickReturn UI pattern. Written from scratch with focus on performance. Demo Usage In your build.grad

Felipe Lima 191 Nov 25, 2022
[] A swipe menu for ListView.

SwipeMenuListView A swipe menu for ListView. Demo Usage Add dependency dependencies { compile 'com.baoyz.swipemenulistview:library:1.3.0' } Step 1

星一 3.5k Dec 16, 2022
A small android library for tagging views inside a ScrollView as "sticky" making them stick to the top of the scroll container until a new sticky view comes and takes it's place

StickyScrollViewItems StickyScrollViewItems is a ScrollView subclass that allowed you to mark items inside the ScrollView as sticky. The items marked

Emil Sjölander 1k Jan 7, 2023
Android library to observe scroll events on scrollable views.

Android-ObservableScrollView Android library to observe scroll events on scrollable views. It's easy to interact with the Toolbar introduced in Androi

Soichiro Kashima 9.6k Dec 30, 2022