为了账号安全,请及时绑定邮箱和手机立即绑定

【备战春招】第21天 通用UI组件开发与基础框架设计

课程名称:移动端架构师


课程章节:通用UI组件开发与基础框架设计

课程讲师:CrazyCodeBoy LovelyChubby


课程内容:

需求分析

设计一个底部导航组件:

  • 能够提供通用的API

  • 支持透明度和底部透出

  • 支持Tab中间高度超过,凸起布局效果

  • 支持iconfont

  • 支持Bitmap

疑难点分析

  • 透明度和底部透出,列表可渲染高度问题

  • 中间高度超过,凸起布局

功能模块拆分

  • 外层容器控件

  • 底部单个Tab控件

  • 每个Tab对应的实体

  • 外层容器控件的对外接口

  • 底部单个Tab控件的对外接口

  • Tab切换监听器

https://img1.sycdn.imooc.com/63f8087c0001d7e824731221.jpg



HiTabTop组件封装

需求分析

设计一个底部导航组件:

  • 能够提供通用的API

  • 支持text

  • 支持Bitmap

  • 支持自动滚动

疑难点分析

  • 自动滚动,实现点击的位置能够自动滚动以展示前后2个

功能模块拆分

  • 外层容器控件

  • 顶部单个Tab控件

  • 每个Tab对应的实体

  • 外层容器控件的对外接口

  • 顶部单个Tab控件的对外接口

  • Tab切换监听器

https://img1.sycdn.imooc.com/63f8089b00013b1924531143.jpg



RecyclerView中使用ViewPager问题

问题

在RecyclerView中使用ViewPager时,会出现两个常见的bug:

  • RecyclerView滚动上去,直至ViewPager看不见,再滚动下来,ViewPager下一次切换没有动画

  • 当ViewPage滚动到一半的时候,RecyclerView滚动上去,再滚动下来,ViewPager会卡在一半

问题1:原因

ViewPager里有一个私有变量mFirstLayout,它是表示是不是第一次显示布局,如果是true,则使用无动画的方式显示当前item,如果是false,则使用动画方式显示当前item。

void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
    ...

    if (mFirstLayout) {
        // We don't have any idea how big we are yet and shouldn't have any pages either.
        // Just set things up and let the pending layout handle things.
        mCurItem = item;
        if (dispatchSelected) {
            dispatchOnPageSelected(item);
        }
        requestLayout();
    } else {
        populate(item);
        scrollToItem(item, smoothScroll, velocity, dispatchSelected);

    ...
}

当ViewPager滚动上去后,因为RecyclerView的回收机制,ViewPager会走onDetachFromWindow,当再次滚动下来时,ViewPager会走onAttachedToWindow,而问题就出在onAttachToWindow。

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    mFirstLayout = true;
}

原来如此,在onAttachedToWindow中,mFirstLayout被重置为true,所以下一次滚动就没有动画。

问题1:解决方法

重写onAttachedToWindow方法,把mFirstLayout再重置成false,因为mFirstLayout是private变量,我们不能直接访问,所以只能反射了。

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    try {
        Field mFirstLayout = ViewPager.class.getDeclaredField("mFirstLayout");
        mFirstLayout.setAccessible(true);
        mFirstLayout.set(this, false);
        getAdapter().notifyDataSetChanged();
        setCurrentItem(getCurrentItem());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

问题2:原因

直接来看ViewPager的onDetachFromWindow方法

@Override
protected void onDetachedFromWindow() {
    removeCallbacks(mEndScrollRunnable);
    // To be on the safe side, abort the scroller
    if ((mScroller != null) && !mScroller.isFinished()) {
        mScroller.abortAnimation();
    }
    super.onDetachedFromWindow();
}

上述代码直接把动画强行停掉了。

问题2:解决方法

想来想去,没什么好办法,只能想办法保护了

@Override
protected void onDetachedFromWindow() {
    if (hasActivityDestroy) {
        super.onDetachedFromWindow();
    }
}

public void setHasDestroy(boolean hasDestroy) {
    hasActivityDestroy= hasDestroy;
}

当activity destroy的时候,给自定义ViewPager一个标志位hasActivityDestroy,只有hasActivityDestroy为true的时候,才调用父类的super.onDetachedFromWindow();



课程收获:

谢谢老师,讲的非常细致,期待后边的继续学习



https://img2.sycdn.imooc.com/63f829d600018f9613800861.jpg

https://img2.sycdn.imooc.com/63fc14d30001d13211460972.jpg


https://img3.sycdn.imooc.com/63fc6a0a0001bd0116050878.jpg




点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
0
获赞与收藏
4

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消