TabLayout|TabLayout 文字/图标/背景动画

介绍 【TabLayout|TabLayout 文字/图标/背景动画】在Tablayout的基础上添加字体或图标的缩放及颜色过渡动画等。
使用的Tablayout的版本:com.google.android.material:material:1.2.1
实现效果如下: TabLayout|TabLayout 文字/图标/背景动画
文章图片

实现功能: 1.修改Indicator动画
2.添加文字缩放及颜色过渡动画
3.添加自定义图标大小及缩放和颜色过渡动画
4.添加背景颜色过渡动画
说明: 文中所有代码块中的 //... 代表省略多行代码
准备: 从库中复制TabLayout、TabItem,TabLayoutMediator三个类到Tabs库并处理掉错误。
Tabs也是需要附加material库,这里主要是修改import和加@SuppressLint("RestrictedApi")注解
1.修改Indicator动画 分析下改Indicator动画的特点,在页面滑动的前一半Indicator 的宽度由短逐渐变长,滑动的后一半Indicator 的宽度再由长逐渐变短。
我们知道Indicator动画是由SlidingTabIndicator来完成的。首先分析下draw方法

@Override public void draw(@NonNull Canvas canvas) { //... // Draw the selection indicator on top of tab item backgrounds if (indicatorLeft >= 0 && indicatorRight > indicatorLeft) { Drawable selectedIndicator; //... selectedIndicator.setBounds(indicatorLeft, indicatorTop, indicatorRight, indicatorBottom); //... selectedIndicator.draw(canvas); } //... }

由此看出只要我们按需求修改indicatorLeft和indicatorRight两个成员变量的值就可以实现需要的效果了。
经过一番努力找到
1.当左右滑动时,onPageScrolled时会调用TabLayout的setScrollPosition方法
public void setScrollPosition(int position, float positionOffset, boolean updateSelectedText, boolean updateIndicatorPosition) { //... // Set the indicator position, if enabled if (updateIndicatorPosition) { slidingTabIndicator.setIndicatorPositionFromTabPosition(position, positionOffset); } //... }

最终需要在updateIndicatorPosition方法中修改即可。修改如下
private void updateIndicatorPosition() { //... //下面注释的是原本代码 //left = (int) (selectionOffset * nextTitleLeft + (1.0f - selectionOffset) * left); //right = (int) (selectionOffset * nextTitleRight + (1.0f - selectionOffset) * right); if (selectionOffset >=0.5){ left = (int) (left + (2*(selectionOffset - 0.5f)*(nextTitleLeft - left))); right = right+(nextTitleRight - right); }else{ right = (int) (right + 2*selectionOffset*(nextTitleRight - right)); } //... }

2.当点TabItem切换时,onPageSelected时会调用TabLayout的selectTab方法
@Override public void onPageSelected(final int position) { final TabLayout tabLayout = tabLayoutRef.get(); //... tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator); //... }

经animateToTab方法
private void animateToTab(int newPosition) { //... // Set the indicator position, if enabled // Now animate the indicator slidingTabIndicator.animateIndicatorToPosition(newPosition, tabIndicatorAnimationDuration); //... }

最终在updateOrRecreateIndicatorAnimation中修改即可。修改如下
void updateOrRecreateIndicatorAnimation(boolean recreateAnimation, final int position, int duration) { //... ValueAnimator.AnimatorUpdateListener updateListener = new ValueAnimator.AnimatorUpdateListener() { @SuppressLint("RestrictedApi") @Override public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) { final float fraction = valueAnimator.getAnimatedFraction(); //下面注释的是原本代码 //setIndicatorPosition( //AnimationUtils.lerp(animationStartLeft, finalTargetLeft, fraction), //AnimationUtils.lerp(animationStartRight, finalTargetRight, fraction)); if (finalTargetLeft - animationStartLeft > 0) { if (fraction >= 0.5f) { float tempF = 2 * (fraction - 0.5f); int tempL = animationStartLeft + Math.round(tempF * (finalTargetLeft - animationStartLeft)); int tempR = animationStartRight + Math.round((finalTargetRight - animationStartRight)); setIndicatorPosition(tempL, tempR); } else { float tempF = 2 * fraction; int tempL = animationStartLeft; int tempR = animationStartRight + Math.round(tempF * (finalTargetRight - animationStartRight)); setIndicatorPosition(tempL, tempR); } }else{ if (fraction >= 0.5f) { float tempF = 2 * (fraction - 0.5f); int tempL = animationStartLeft + Math.round((finalTargetLeft - animationStartLeft)); int tempR = animationStartRight + Math.round(tempF*(finalTargetRight - animationStartRight)); setIndicatorPosition(tempL, tempR); }else{ float tempF = 2 * fraction; int tempL = animationStartLeft + Math.round(tempF * (finalTargetLeft - animationStartLeft)); int tempR = animationStartRight ; setIndicatorPosition(tempL, tempR); } } } }; //... }

到这里Indicator动画就修改结束了。
2.添加文字缩放及颜色过渡动画 选中字体和将选中的字体大小及颜色过渡动画。首先在value.xml中添加

字体颜色就使用已有的tabSelectedTextColor和tabTextColor。
由于显示的文字是TabView的子View,所以文字缩放及颜色的动画都需要在TabView中完成。
第一步:仿照Indicator动画,在TabView中
1.当左右滑动时 ,添加setPositionFromTabPosition方法
2.当点TabItem切换时,添加animateFromTabPosition方法
由于代码有点多,这里就不在上代码了。文末会附上源码地址
第二步:与Indicator相似分别在相应的位置调用第一步添加的方法。
在setScrollPosition方法中
public void setScrollPosition( int position, float positionOffset, boolean updateSelectedText, boolean updateIndicatorPosition) { //... // Set the indicator position, if enabled if (updateIndicatorPosition) { slidingTabIndicator.setIndicatorPositionFromTabPosition(position, positionOffset); } if (updateIndicatorPosition) { Tab selectedTempTab = getTabAt(position); if (selectedTempTab != null) { selectedTempTab.view.setPositionFromTabPosition(position, positionOffset); int nextIndex = position + 1; if (positionOffset == 0) { if (nextPositionOffset > 0.5) { nextIndex = position - 1; } else { nextIndex = position + 1; }} Tab nextTab = getTabAt(nextIndex); if (nextTab != null) { nextTab.view.setPositionFromTabPosition(nextIndex, 1f - positionOffset); } nextPositionOffset = positionOffset; } } //... }

在animateToTab方法中
private void animateToTab(int newPosition) { //... // Set the indicator position, if enabled // Now animate the indicator slidingTabIndicator.animateIndicatorToPosition(newPosition, tabIndicatorAnimationDuration); if (newPosition != getSelectedTabPosition()){ Tab toTab = getTabAt(newPosition); Tab fromTab = getTabAt(getSelectedTabPosition()); if (toTab != null && fromTab != null){ toTab.view.animateFromTabPosition(false,tabIndicatorAnimationDuration); fromTab.view.animateFromTabPosition(true,tabIndicatorAnimationDuration); } } //... }

至此文字的缩放及颜色动画的大致流程就说完了。具体细节如给文字预留一些距离等请查看源码。
3.添加自定义图标大小及缩放和颜色过渡动画 由于图标的缩放和颜色过渡动画和文字的非常相似,这里就不再叙说。
首先呢,这里说的自定义图标大小是自定义默认的图标大小,即tab.setIcon中的Icon大小。
实现思路:在setIcon时给ImageView设置大小。如下
@NonNull public Tab setIcon(@Nullable Drawable icon) { this.icon = icon; //... view.initIconView(); return this; }

void initIconView(){ LinearLayout.LayoutParams lp = (LayoutParams) iconView.getLayoutParams(); if (tabIconWidth != 0) { lp.width = tabIconWidth; } if (tabIconHeight != 0){ lp.height = tabIconHeight; } iconView.setLayoutParams(lp); }

4.添加背景颜色过渡动画 实现方式和文字颜色过渡是相似的,这里就不再重复。
需注意点:
1.原本TabView的背景是设置的是点击水波纹效果,设置背景过渡动画会去除水波纹效果,动画结束需要重新设置点击水波纹效果
2.TabView的背景遮挡Indicator动画。需要把SlidingTabIndicator的draw方法的super.draw放到第一句
@Override public void draw(@NonNull Canvas canvas) { // Draw the tab item contents (icon and label) on top of the background + indicator layers super.draw(canvas); //... }

至此本文已结束。
特奉上 源码 该Library应用于小说阅读器 Z阅读

    推荐阅读