KunMinX / Linkage-RecyclerView

即使不用饿了么订餐,也请务必收藏好该库!🔥 一行代码即可接入,二级联动订餐列表。
3.65k stars 458 forks source link

向下滑动时,在两个组别切换的时候,假头会闪一下,Demo中也会出现这个现象 #41

Open WanDa1993 opened 3 years ago

WanDa1993 commented 3 years ago

研究源码的过程中,测试发现的。不算大问题,算是一个小瑕疵。顺便感谢下作者~

WanDa1993 commented 3 years ago

组别:A B C D E 。。。。 向上滑动 从 D -> C 临界切换的时候会闪一下。

WanDa1993 commented 3 years ago
                if (mFirstVisiblePosition != firstPosition && firstPosition >= 0) {
                    mFirstVisiblePosition = firstPosition;
                    mTvHeader.setY(0);

                    String currentGroupName = items.get(mFirstVisiblePosition).isHeader
                            ? items.get(mFirstVisiblePosition).header
                            : items.get(mFirstVisiblePosition).info.getGroup();

                    if (TextUtils.isEmpty(mLastGroupName) || !mLastGroupName.equals(currentGroupName)) {
                        mLastGroupName = currentGroupName;
                        groupNameChanged = true;
                        mTvHeader.setText(mLastGroupName);
                    }
                }

应该在临界的时候 先触发这段代码,先设置Header Y 坐标 = 0 ,然后赋值

WanDa1993 commented 3 years ago

然后才执行这段逻辑

            if (firstCompletePosition > 0 && (firstCompletePosition) < items.size()
                    && items.get(firstCompletePosition).isHeader) {

                View view = mSecondaryLayoutManager.findViewByPosition(firstCompletePosition);
                if (view != null && view.getTop() <= mTitleHeight) {
                    mTvHeader.setY(view.getTop() - mTitleHeight);
                }
            }

上移Header

才会造成闪一下

WanDa1993 commented 3 years ago

问题我找到了解决思路,在重新描述下问题,以及解决思路,供作者参考:

问题产生场景:

已知组别:A、B、C、D、E

已知占位Header:tvHeader

复现步骤:

(1)先滑动到tvHeader与组别B的头部重合,此时tvHeader显示B

(2)慢速向上滑动,只到A组的底部刚刚出现的临界

(3)tvHeader 会迅速更新成A的名称,然后进行tvHeader.y = -titleHeight的操作

(4)此时会发现tvHeader名称变化成A,然后闪烁一下,之后又显示B组别的Title,这个过程比较快。很容易复现出来

WanDa1993 commented 3 years ago

解决方案:

研究下源码,造成这个现象是由于如下代码造成的

LinkageRecyclerView#200

                boolean groupNameChanged = false;

                if (mFirstVisiblePosition != firstPosition && firstPosition >= 0) {
                    mFirstVisiblePosition = firstPosition;
                    mTvHeader.setY(0);

                    String currentGroupName = items.get(mFirstVisiblePosition).isHeader
                            ? items.get(mFirstVisiblePosition).header
                            : items.get(mFirstVisiblePosition).info.getGroup();

                    if (TextUtils.isEmpty(mLastGroupName) || !mLastGroupName.equals(currentGroupName)) {
                        mLastGroupName = currentGroupName;
                        groupNameChanged = true;
                        mTvHeader.setText(mLastGroupName);
                    }
                }

上面这段的代码,我理解的含义是只要发生第一个可见的Item变化,此时就会将tvHeader的y坐标设置成0,然后刷新tvHeader的text

造成原因:

其实在第一个可见Item切换时,会存在两种情况

(1)向下滑动 && 第一个可见Item变化

(2)向上滑动 && 第一个可见Item变化

向下滑动:

向下滑动时&&第一个Item变化,因为此时tvHeader和SecondaryRv的标题Item并不重合,所以不需要重置tvHeader的Y轴坐标,闪烁的本质也是因为重置Y坐标,同时更新Text

向上滑动:

向上滑动时&&第一个Item变化,需要重置tvHeader的Y轴坐标,因为此时tvHeader和SecondaryRv的标题Item重合

WanDa1993 commented 3 years ago

解决方案:


                if (firstCompletePosition > 0 && (firstCompletePosition) < items.size()
                        && items.get(firstCompletePosition).isHeader) {

                    View view = mSecondaryLayoutManager.findViewByPosition(firstCompletePosition);
                    if (view != null && view.getTop() <= mTitleHeight) {
                        mTvHeader.setY(view.getTop() - mTitleHeight);
                    }
                } else {
                    //改动二: 如果不进行粘性头的操作时,此时重置Y轴坐标
                    mTvHeader.setY(0);
                }

                // Here is the logic of group title changes and linkage:

                boolean groupNameChanged = false;

                if (mFirstVisiblePosition != firstPosition && firstPosition >= 0) {

                    //改动一: 只判断上滑时,才会重置mTvHeader的Y轴坐标
                    if (mFirstVisiblePosition < firstPosition) {
                        mTvHeader.setY(0);
                    }

                    mFirstVisiblePosition = firstPosition;

                    String currentGroupName = items.get(mFirstVisiblePosition).isHeader
                            ? items.get(mFirstVisiblePosition).header
                            : items.get(mFirstVisiblePosition).info.getGroup();

                    if (TextUtils.isEmpty(mLastGroupName) || !mLastGroupName.equals(currentGroupName)) {
                        mLastGroupName = currentGroupName;
                        groupNameChanged = true;
                        mTvHeader.setText(mLastGroupName);
                    }
                }
KunMinX commented 3 years ago

@Vander-liu

非常感谢你的细心测试和反馈,已提交修改 😉