平方X

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2724|回复: 0

RecyclerView Item 设为不可见后无法刷新

[复制链接]

414

主题

709

帖子

3602

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3602
QQ
发表于 2017-11-2 12:27:14 | 显示全部楼层 |阅读模式
[md]

无法下拉刷新,想起以前添加 decoration 以后,就可以正常刷新了。  
试了一下果然,这一次寻找一下原因,最后发现还是因为隐藏某个 item 后造成的,就不应该隐藏。

调试后发现
```

com.aspsine.swipetoloadlayout.SwipeToLoadLayout#onInterceptTouchEvent
中调用的 onCheckCanRefresh 始终返回 false,也就是不可以刷新。
com.aspsine.swipetoloadlayout.SwipeToLoadLayout#onCheckCanRefresh
com.aspsine.swipetoloadlayout.SwipeToLoadLayout#canChildScrollUp 始终返回 true
com.aspsine.swipetoloadlayout.SwipeToLoadLayout2#canChildScrollUp 重写的
com.aspsine.swipetoloadlayout.SwipeToLoadLayout2#canViewScrollUp
发现在计算 recyclerView 时
//⑥
android.support.v4.view.ViewCompat#canScrollVertically(view,-1) 返回 true
android.view.View#canScrollVertically
    /**
     * Check if this view can be scrolled vertically in a certain direction.
     *
     * @param direction Negative to check scrolling up, positive to check scrolling down.
     * @return true if this view can be scrolled in the specified direction, false otherwise.
     */
    public boolean canScrollVertically(int direction) {
        //④
        final int offset = computeVerticalScrollOffset();
        final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
        if (range == 0) return false;
        if (direction < 0) {
            //⑤
            return offset > 0;
        } else {
            return offset < range - 1;
        }
    }
看 recyclerView 是如何计算 computeVerticalScrollOffset() 的
android.support.v7.widget.RecyclerView#computeVerticalScrollOffset
转给 LayoutManager
android.support.v7.widget.LinearLayoutManager#computeVerticalScrollOffset
android.support.v7.widget.LinearLayoutManager#computeScrollOffset
    private int computeScrollOffset(RecyclerView.State state) {
        if (getChildCount() == 0) {
            return 0;
        }
        ensureLayoutState();
        return ScrollbarHelper.computeScrollOffset(state, mOrientationHelper,
                findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true),
                findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true),
                this, mSmoothScrollbarEnabled, mShouldReverseLayout);
    }
计算第一个可见 child
android.support.v7.widget.LinearLayoutManager#findFirstVisibleChildClosestToStart
android.support.v7.widget.LinearLayoutManager#findOneVisibleChild

    View findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible,
            boolean acceptPartiallyVisible) {
        ensureLayoutState();
        final int start = mOrientationHelper.getStartAfterPadding();
        final int end = mOrientationHelper.getEndAfterPadding();
        final int next = toIndex > fromIndex ? 1 : -1;
        View partiallyVisible = null;
        for (int i = fromIndex; i != toIndex; i+=next) {
            final View child = getChildAt(i);
            final int childStart = mOrientationHelper.getDecoratedStart(child);
            // ①
            final int childEnd = mOrientationHelper.getDecoratedEnd(child);
            if (childStart < end && childEnd > start) {
                if (completelyVisible) {
                    if (childStart >= start && childEnd <= end) {
                        return child;
                    } else if (acceptPartiallyVisible && partiallyVisible == null) {
                        partiallyVisible = child;
                    }
                } else {
                    return child;
                }
            }
        }
        return partiallyVisible;
    }
android.support.v7.widget.OrientationHelper#getDecoratedEnd

android.support.v7.widget.ScrollbarHelper#computeScrollOffset

    static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
            View startChild, View endChild, RecyclerView.LayoutManager lm,
            boolean smoothScrollbarEnabled, boolean reverseLayout) {
        if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
                endChild == null) {
            return 0;
        }
        //②
        final int minPosition = Math.min(lm.getPosition(startChild),
                lm.getPosition(endChild));
        final int maxPosition = Math.max(lm.getPosition(startChild),
                lm.getPosition(endChild));
        //③
        final int itemsBefore = reverseLayout
                ? Math.max(0, state.getItemCount() - maxPosition - 1)
                : Math.max(0, minPosition);
        if (!smoothScrollbarEnabled) {
            return itemsBefore;
        }
        final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) -
                orientation.getDecoratedStart(startChild));
        final int itemRange = Math.abs(lm.getPosition(startChild) -
                lm.getPosition(endChild)) + 1;
        final float avgSizePerRow = (float) laidOutArea / itemRange;

        return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
                - orientation.getDecoratedStart(startChild)));
    }


设置了 decoration ,使得①中第0个隐藏的 headerView 可见,②③得出的 itemsBefore 为0,返回到④为0,⑤返回 false,到⑥返回 false 可以刷新。
示设置 decoration , 使得①中第0个隐藏的 headerView 不可见,②③得出的 itemsBefore 为1,返回到④有值,⑤返回 true,到⑥返回 false 不可以刷新。
```

到此处,就和之前研初过的 item 设置为 GONE 时仍占用高度的问题连起来了。
要想让 item 设为 GONE,应该在外面包裹一层 ViewGroup,然后手动设置为 GONE
但设置为 GONE,又会导致计算 itemsBefore 时,认为前面还有一个item。



[/md]
我是平方X~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|Archiver|平方X ( 冀ICP备14018164号 )

GMT+8, 2024-4-26 13:09 , Processed in 0.124526 second(s), 21 queries .

技术支持:Powered by Discuz!X3.4  © 2001-2013 Comsenz Inc.

版权所有:Copyright © 2014-2018 平方X www.pingfangx.com All rights reserved.

快速回复 返回顶部 返回列表