Recyclerviews and SwipeRefreshLayout using support library 23.2.0

前端 未结 3 1461
暖寄归人
暖寄归人 2021-01-05 12:39

Has anyone figured out a way to get recyclerviews, AppbarLayouts and SwipeRefreshLayout to work together on 23.2 yet? I am using a pretty standard method I think, but the sw

相关标签:
3条回答
  • 2021-01-05 13:19

    attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="ImprovedSwipeLayoutAttrs">
            <attr name="scrollableChildId" format="reference" />
        </declare-styleable>
    </resources>
    

    layout.xml

    <in.nerd_is.inactive_weibo.ui.ImprovedSwipeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:fab="http://schemas.android.com/apk/res-auto"
        xmlns:isl="http://schemas.android.com/apk/res-auto"
        android:id="@+id/swipe_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/md_blue_grey_50"
        isl:scrollableChildId="@+id/list_statuses"
        tools:context="in.nerd_is.inactive_weibo.ui.StatusesFragment" >
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <ListView
                android:id="@+id/list_statuses"
                android:minHeight="?android:attr/listPreferredItemHeight"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingTop="12dp"
                android:paddingBottom="12dp"
                android:paddingLeft="8dp"
                android:paddingRight="8dp"
                android:clipToPadding="false"
                android:divider="@android:color/transparent"
                android:dividerHeight="12dp"/>
    
            <com.melnykov.fab.FloatingActionButton
                android:id="@+id/button_floating_action"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom|right"
                android:layout_margin="16dp"
                android:src="@drawable/ic_md_create"
                fab:fab_colorNormal="@color/md_blue_400"
                fab:fab_colorPressed="@color/md_blue_grey_500"/>
        </FrameLayout>
    
    </in.nerd_is.inactive_weibo.ui.ImprovedSwipeLayout>
    

    ImprovedSwipeLayout.java

    public class ImprovedSwipeLayout extends SwipeRefreshLayout {
    
        private static final String TAG = ImprovedSwipeLayout.class.getCanonicalName();
        private int mScrollableChildId;
        private View mScrollableChild;
    
        public ImprovedSwipeLayout(Context context) {
            this(context, null);
        }
    
        public ImprovedSwipeLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            TypedArray a = context.obtainStyledAttributes(
                    attrs, R.styleable.ImprovedSwipeLayoutAttrs);
            mScrollableChildId = a.getResourceId(R.styleable.ImprovedSwipeLayoutAttrs_scrollableChildId, 0);
            mScrollableChild = findViewById(mScrollableChildId);
            a.recycle();
        }
    
        @Override
        public boolean canChildScrollUp() {
            ensureScrollableChild();
    
            if (android.os.Build.VERSION.SDK_INT < 14) {
                if (mScrollableChild instanceof AbsListView) {
                    final AbsListView absListView = (AbsListView) mScrollableChild;
                    return absListView.getChildCount() > 0
                            && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                            .getTop() < absListView.getPaddingTop());
                } else {
                    return mScrollableChild.getScrollY() > 0;
                }
            } else {
                return ViewCompat.canScrollVertically(mScrollableChild, -1);
            }
        }
    
        private void ensureScrollableChild() {
            if (mScrollableChild == null) {
                mScrollableChild = findViewById(mScrollableChildId);
            }
        }
    
    }
    

    It's from http://nerd-is.in/2014-09/add-multi-child-view-in-swiperefreshlayout/

    Create a View extend SwipeRefreshLayout and custom canChildScrollUp.

    0 讨论(0)
  • 2021-01-05 13:19

    Faced same issue after updating to 23.2.0. It's an old-new bug which was fixed in 23.1.1 and appears again in 23.2.0.

    In my case I downgrade to 23.1.1 and everithing is OK again. So we should wait for new version of libs or use workarounds with overriding SwipeRefreshLayout.


    Here is link to google bugtracker: RecyclerView v23.2.0 - doesn't play nicely with SwipeRefreshLayout

    0 讨论(0)
  • 2021-01-05 13:30

    If you put a View that doesn't implement ScrollingView or isn't an AbsListView into SwipeRefreshLayout, SwipeRefreshLayout#canChildScrollUp() always returns false.

    So by using a FrameLayout inside of SwipeRefreshLayout you have two issues:

    1. SwipeRefreshLayout doesn't accept nested scroll operations of descendant views (see SwipeRefreshLayout#onStartNestedScroll(View, View, int)). This causes the issues with CoordinatorLayout / AppBarLayout.

    2. The SwipeRefreshLayout handles touch events itself as long as its child cannot scroll up or there is no nested scroll in progress (see SwipeRefreshLayout#onInterceptTouchEvent(MotionEvent) and SwipeRefreshLayout#onTouchEvent(MotionEvent)). This means the spinner is displayed when "touch moving down".

    You can fix this by using your own SwipeRefreshLayout, which overwrites SwipeRefreshLayout#onStartNestedScroll(View, View, int). This way nested scrolls are accepted even if the direct child view can't scroll up:

    public class SwipeRefreshLayout extends android.support.v4.widget.SwipeRefreshLayout {
    
        public SwipeRefreshLayout(Context context) {
            super(context);
        }
    
        public SwipeRefreshLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
            return isEnabled()
                    && !isRefreshing()
                    && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
        }
    }
    

    BTW if you look at SwipeRefreshLayout's code in 23.1.1 you'll see, that the canChildScrollUp() check was removed but was added again in 23.2.0. I also removed the check for !mReturningToStart, because mReturningToStart is always false.

    0 讨论(0)
提交回复
热议问题