介绍
在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方法
@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);
//...
}
至此本文已结束。