第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

使用系統(tǒng)TabLayout的app快來(lái)修Bug

標(biāo)簽:
Android

前言

系统 TabLayout 和 ViewPager 配合使用时有个 Bug,当切换 Tab 的时候,Tab 会整体往左抖一下,这个抖动速度很快,大家稍微注意点能看到,那么笔者在公司做业务时也有使用到系统的 TabLayout ,进行视觉校验的时候没逃过设计师的法眼,设计师要求高是件好事,但这个时候重新写一个也不现实,那么该怎么办呢?

问题描述

先来看看直接使用系统 TabLayout 而出现问题的一些App:

             5b8006a00001199d03760340.jpg5b8006af00012a6a03150115.jpg5b8006ba0001d64803980261.jpg                           


问题分析

在分析问题之前,我们先回顾下这个 Bug 复现的场景:先选中一个靠后的 Tab,然后滑动 TabLayout 到最左边,点击第一个 Tab,会发现整个 TabLayout 往左抖了一下,速度很快,但无法忽视

那么我们要解决的就是快速抖动的问题。

想解决这个问题,TabLayout 的源码还是得分析的,TabLayout 直接继承的 HorizontalScrollView,不难推测,抖动的产生其实就是被执行了 scroll。

我们回想下,让 TabLayout 发生 scroll 行为的场景会有哪些?

o    直接选中指定 Tab

o    滑动 ViewPager

我们发现的 Bug 出现的场景是点击 Tab 发生的,那么我们点击了 Tab 后符合上面说的场景一,那么 Tab 切换后会导致 ViewPager 滑动,那也会触发 scroll,擦,难道就是因为这样,导致了闪了一下?只能看看源码了:

首先看看点击 Tab 触发的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// TabLayout#selectTab
void selectTab(final Tab tab, boolean updateIndicator) {
   final Tab currentTab = mSelectedTab;
   if (currentTab == tab) {
       ...
   } else {
       final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
       if (updateIndicator) {
           if ((currentTab == null || currentTab.getPosition() == Tab.INVALID_POSITION)
                   && newPosition != Tab.INVALID_POSITION) {
               ...
           } else {
               // 让 Tab 做动画
               animateToTab(newPosition);
           }
           ...
       }
       ...
   }
}

再看 TabLayout#animateToTab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void animateToTab(int newPosition) {
   if (newPosition == Tab.INVALID_POSITION) {
       return;
   }
   ...
   
   final int startScrollX = getScrollX();
   final int targetScrollX = calculateScrollXForTab(newPosition, 0);
   if (startScrollX != targetScrollX) {
       // 创建 scroll 动画
       ensureScrollAnimator();
       mScrollAnimator.setIntValues(startScrollX, targetScrollX);
       // scroll 动画开始执行
       mScrollAnimator.start();
   }
   // Now animate the indicator
   mTabStrip.animateIndicatorToPosition(newPosition, ANIMATION_DURATION);
}

再看看 ensureScrollAnimator 做了啥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void ensureScrollAnimator() {
   if (mScrollAnimator == null) {
       mScrollAnimator = new ValueAnimator();
       mScrollAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
       mScrollAnimator.setDuration(ANIMATION_DURATION);
       mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
           @Override
           public void onAnimationUpdate(ValueAnimator animator) {
               // 属性动画回调中调用 scrollTo
               scrollTo((int) animator.getAnimatedValue(), 0);
           }
       });
   }
}

可以看到点击 Tab 最终会使 TabLayout 发生 scroll 行为。

继续顺着刚才说的点击 Tab 的时候也会触发 ViewPager 的滑动,我们看看 ViewPager 滑动方法里做了啥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// TabLayout#TabLayoutOnPageChangeListener
public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {
   ...
   @Override
   public void onPageScrolled(final int position, final float positionOffset,
           final int positionOffsetPixels) {
       final TabLayout tabLayout = mTabLayoutRef.get();
       if (tabLayout != null) {
           ...
           // 这里又调用了设置 Scroll 的位置的方法
           tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
       }
   }
   ...
}

再看看 setScrollPosition :

1
2
3
4
5
6
void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
        boolean updateIndicatorPosition) {
    ...
    scrollTo(calculateScrollXForTab(position, positionOffset), 0);
    ...
}

看到了吧,这里也调用了 scrollTo。

那么之前抖动的问题就很显然了,点击 Tab 的时候会触发 TabLayout 的scrollTo,而点击 Tab 会触发ViewPager 滑动,ViewPager的滑动也特么触发了 scrollTo,这 ViewPager 滑动导致的 scrollTo 就是我们闪烁的原因!

分析完毕,如何解决呢?

解决

其实解决方案很简单,我们只要使点击 Tab 的时候不触发 ViewPager 滑动的那个 scrollTo 就行了。

How?

我们在自己滑动 ViewPager 的时候 scrollTo 还是要走的,那么自己滑动和点击 Tab 触发的 ViewPager 滑动有啥区别呢?当然有!pageScrollState 不同!自己滑动的时候是 SCROLL_STATE_DRAGGING,而点击 Tab 时是 SCROLL_STATE_IDLE。

那么显而易见了,通过 pageScrollState 来区分下就行了。

我们需要对刚刚分析的 TabLayoutOnPageChangeListener 类的实现做点改变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static class FixedTabLayoutOnPageChangeListener
       extends TabLayout.TabLayoutOnPageChangeListener {
   private boolean isTouchState;
   public FixedTabLayoutOnPageChangeListener(TabLayout tabLayout) {
       super(tabLayout);
   }
   @Override
   public void onPageScrollStateChanged(int state) {
       super.onPageScrollStateChanged(state);
       if (state == SCROLL_STATE_DRAGGING) {
           isTouchState = true;
       } else if (state == SCROLL_STATE_IDLE) {
           isTouchState = false;
       }
   }
   @Override
   public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       if (isTouchState) {
           super.onPageScrolled(position, positionOffset, positionOffsetPixels);
       }
   }
}

只有 pageScrollState 是 SCROLL_STATE_DRAGGING 的时候才触发 TabLayoutOnPageChangeListener 的 onPageScrolled。

但是 TabLayoutOnPageChangeListener 是 TabLayout 的 mPageChangeListener 变量,我们需要替换它,那只能反射了。

1
2
3
4
5
6
7
8
9
try {
  Field field = TabLayout.class.getDeclaredField("mPageChangeListener");
  field.setAccessible(true);
  field.set(this, new FixedTabLayoutOnPageChangeListener(this));
} catch (NoSuchFieldException e) {
  e.printStackTrace();
} catch (IllegalAccessException e) {
  e.printStackTrace();
}

这样一来,就完成了,看看效果:

5b8006d9000146e101260014.jpg


尾语

即使是官方的东西但难免也会有点小问题,重视细节,再解决它,这个过程还是不错的。

原文链接:http://www.apkbus.com/blog-822721-77046.html

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫(xiě)下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶(hù)
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專(zhuān)欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消