Android实现双层tab悬停布局的踩坑记录

效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

踩坑

1.CoordinatorLayout+CoordinatorLayout只能实现第一层tab和第二层tab悬停,但是无法实现页面整体上移
2.监听子页面的滑动距离,并将距离传递给父页面的相应控件,让其滚动到相应位置,向上滚动没问题,但是无法向下滚动
3.CoordinatorLayout+NestedScrollView+CoordinatorLayout能够实现页面上移,但是只能实现第一层tab悬停,无法实现第二层tab悬停
4.NestedScrollView+RecyclerView导致item不复用
5.页面滑动冲突`

实现

刚从ui小姐姐手上接过ui图的时候,我的内心是无比崩溃的,首先是这个布局之前一直没有做过;其次是我觉得页面从设计上面来说是不太合理的,因为咋一看页面嵌套实在是太多了;最后就是我所想到的方法,需要使用大量均有滑动事件的控件进行嵌套来实现这样的布局,解决滑动冲突对我来说一直是一个比较头疼的事情。

不过崩溃归崩溃,自己选择的路,哭着也要把他走完…

最外层布局

我在网上查阅了大量的资料,查询到的几乎都是只有一个tab悬停,未找到双层tab悬停的示例。找到的资料中,实现悬停主要有两种方式,一种是利用CoordinatorLayout+AppBarLayout的方式,另一种是利用RecyclerView。我结合我们的需求,决定首先采用第一种方式先实现第一层的tab悬停,即最外层布局为CoordinatorLayout,然后将需要悬停的布局A(我这里是一个用MagicIndicator实现的tab)以及需要随A布局一起向上滚动的布局B(我这里是一个搜索栏和一个按钮)放入AppBarLayout中,我这里给布局B设置了属性 app:layout_scrollFlags=“scroll|snap”,让其可以随页面一起向上滚动,并且设置他要么向上全部滚出屏幕,要么向下全部滚进屏幕。A布局不设置相关属性,这样便能实现B布局先向上滚动,B布局到顶悬停的功能。AppBarLayout以外的布局是一个ViewPager,用于切换各fragment(我要讲的主要是其中一个需要实现二层tab悬停功能的子页面),这部分需要设置 app:layout_behavior="@string/appbar_scrolling_view_behavior",这样这部分布局就能正常显示在悬停布局A的下面。这一部分的实现没有任何问题。

第二层悬停tab

由于没有找到相关实例,我进行了几种我认为可行的尝试。

第一种
由于第一层使用CoordinatorLayout+AppBarLayout的方式能正常实现悬停功能,所以我在子页面中也预备使用这种布局,但是后来发现这样虽然可以实现子页面的tab悬停在第一层tab下的功能,但是我最外层布局中的B布局(搜索栏部分)无法跟随页面滑动。为了让其滚动,我给子页面中的AppBarLayout注册了OnOffsetChangedListener监听,来监听他的滚动距离,然后将这个距离传递到父布局中,让父布局中的AppBarLayout也跟随移动子布局中滚动的距离,令人兴奋的是,能够成功达到期望的效果。但是在我兴奋之余,却发现了问题。由于我的最外层布局中,一共包含了四个子页面,除了当前子页面,其他子页面也可以滑动页面,当我在其他页面进行向上滑动后,在当前子页面无法将其滑下来,因为此时子页面中的AppBarLayout的滑动距离为0,所以这个方法只有放弃。

第二种
经过查阅资料,我发现如果要实现在子页面中任意位置向上滑动页面,父布局中的搜索栏要跟随一起向上滑动的效果,需要在子页面中添加NestedScrollView效果,即需要采用CoordinatorLayout+AppBarLayout+NestedScrollView这样的布局,所以我在第一种方法的基础之上,添加了NestedScrollView,即在子页面最外层添加了NestedScrollView,此时的页面整体嵌套布局相当于是CoordinatorLayout+AppBarLayout+ViewPager+NestedScrollView+CoordinatorLayout+AppBarLayout+ViewPager,这样发现虽然能实现页面搜索栏一起上移的功能,但是无法实现第二个tab栏悬停的功能,所以这个方法也只好放弃

第三种
在查阅资料的过程中,我偶然翻阅到了一位大神分享的一篇标题为 Android NestedScrollView滚动到顶部固定子View悬停挂靠粘在顶端的文章,然后我决定直接使用大神的这个控件来实现子view中的tab悬停功能,此时页面的布局结构为CoordinatorLayout+AppBarLayout+ViewPager+NestedScrollView+RecyclerView(禁用了RecyclerView的滑动,让NestedScrollView滑动,通过监听NestedScrollView是否到底部来触发RecyclerView的加载更多),最终实现了ui小姐姐想要的效果。正当我以为大功告成的时候,测试告诉我说,好卡鸭,能不能优化优化,我开始还以为是人家手机问题,后来用自己手机一试,当RecyclerView加载三四页之后,简直卡到怀疑人生,后来才发现,原来NestedScrollView嵌套RecyclerView,如果把RecyclerView的滑动事件禁用了,会导致RecyclerView的复用失效,瞬间崩溃…具体分析可以参照解决NestedScrollView与RecyclerView嵌套,导致RecyclerView无法复用,滑动冲突等问题这篇文章

第四种
由于这个版本开发任务很重,上线时间紧,我只有想一个改动尽可能小的方法。所以查阅了一下NestedScrollView嵌套RecyclerView,让RecyclerView能复用的方法。答案就是不要禁用RecyclerView的滑动事件,但是这样的后果就是RecyclerView一直加载,直到将所有数据加载完毕,这样毋庸置疑是不行的。幸运的是,可以给RecyclerView设置一个固定高度,这样就可以避免以上所说的问题。所以我将布局中的RecyclerView替换成了之前自定义的一个可设置最大高度的控件MaxHeightRecyclerView,并将其最大高度设置为屏幕高度。但是这样又有一个问题,就是滑动页面时只能滑动RecyclerView,RecyclerView以上的其他区域无法滑动,此时的我心中已是万马奔腾。后来在绝望之中翻阅到了一篇文章,NestScrolling 实践——ScrollView与RecyclerView的完美衔接,阅读之后我对之前找到的那个StickyNestedScrollView控件代码进行了改变,改写了StickyNestedScrollView控件的onNestedPreScroll方法

@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed, int type) {
    if (GlobalUtil.mainTabIsTop && dy > 0) {
        if(currentlyStickingView==null) {
            scrollBy(0, dy);
            consumed[1] = dy;
            return;
        }
    }
    super.onNestedPreScroll(target, dx, dy, consumed, type);
}

即当父布局中的一级tab处于悬停状态并且是向上滑动时,如果子页面中二级tab不处于悬停状态,那么就使StickyNestedScrollView滚动页面所滚动的距离,这样能实现页面整体向上滚动,而其他情况,直接进入父类的onNestedPreScroll方法,这样也不存在滑动冲突

另外还有个小问题就是,我在使用StickyNestedScrollView实现悬停功能时,当从页面顶部向上飞速滑动页面时,子页面的tab在悬停的前一瞬间,会和上面的view有一个很小裂缝一样的间隙,我也不知道具体原因,所以我将StickyNestedScrollView换成了另一个自定义view StickyNestedScrollLayout,并改写了他的onNestedPreScroll方法。

至此,该功能基本算是圆满完成了,希望不要再发现什么奇葩问题,我实在是承受不起了555…

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值