当前位置: 代码迷 >> 综合 >> TabLayout 文字/图标/背景动画
  详细解决方案

TabLayout 文字/图标/背景动画

热度:24   发布时间:2024-02-25 04:02:33.0

介绍

在Tablayout的基础上添加字体或图标的缩放及颜色过渡动画等。

使用的Tablayout的版本:com.google.android.material:material:1.2.1

实现效果如下:
效果图

实现功能:

1.修改Indicator动画

2.添加文字缩放及颜色过渡动画

3.添加自定义图标大小及缩放和颜色过渡动画

4.添加背景颜色过渡动画

说明:

文中所有代码块中的 //… 代表省略多行代码

准备:

从库中复制TabLayout、TabItem,TabLayoutMediator三个类到Tabs库并处理掉错误。

Tabs也是需要附加material库,这里主要是修改import和加@SuppressLint(“RestrictedApi”)注解

1.修改Indicator动画

分析下改Indicator动画的特点,在页面滑动的前一半Indicator 的宽度由短逐渐变长,滑动的后一半Indicator 的宽度再由长逐渐变短。

我们知道Indicator动画是由SlidingTabIndicator来完成的。首先分析下draw方法

@Overridepublic void draw(@NonNull Canvas canvas) {
    //...// Draw the selection indicator on top of tab item backgroundsif (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 enabledif (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 indicatorslidingTabIndicator.animateIndicatorToPosition(newPosition, tabIndicatorAnimationDuration);//...
}

最终在updateOrRecreateIndicatorAnimation中修改即可。修改如下

void updateOrRecreateIndicatorAnimation(boolean recreateAnimation, final int position, int duration) {
    //...ValueAnimator.AnimatorUpdateListener updateListener =new ValueAnimator.AnimatorUpdateListener() {
    @SuppressLint("RestrictedApi")@Overridepublic 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中添加

<declare-styleable name="TabLayout">
<!-- text选择时的文字大小 不设置 没有字体缩放动画--><attr name="tabSelectedTextSize" format="dimension" />
<!-- text的默认文字大小 --><attr name="tabTextSize" format="dimension" />
</declare-styleable>

字体颜色就使用已有的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 enabledif (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 indicatorslidingTabIndicator.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 layerssuper.draw(canvas);//...
}

至此本文已结束。

特奉上 源码

该Library应用于小说阅读器 Z阅读