package it.sephiroth.android.library.bottomnavigation; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.support.v4.view.ViewCompat; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import it.sephiroth.android.library.bottonnavigation.R; import proguard.annotation.Keep; /** * Created by alessandro on 4/3/16 at 10:55 PM. * Project: MaterialBottomNavigation */ @SuppressLint ("ViewConstructor") public class BottomNavigationFixedItemView extends BottomNavigationItemViewAbstract { private static final String TAG = BottomNavigationFixedItemView.class.getSimpleName(); private final int iconSize; private int centerY; private final Interpolator interpolator = new DecelerateInterpolator(); private float textWidth; private long animationDuration; private final int colorActive; private final int colorInactive; private final int colorDisabled; private final int paddingTopActive; private final int paddingTopInactive; private final int paddingBottom; private final int paddingHorizontal; private final int textSizeInactive; private static final float TEXT_SCALE_ACTIVE = 1.1666666667f; private float canvasTextScale; private float iconTranslation; private int textCenterX; private int textCenterY; private int centerX; private float textX; private float textY; public BottomNavigationFixedItemView(final BottomNavigation parent, boolean expanded, final MenuParser.Menu menu) { super(parent, expanded, menu); final Resources res = getResources(); this.paddingTopActive = res.getDimensionPixelSize(R.dimen.bbn_fixed_item_padding_top_active); this.paddingTopInactive = res.getDimensionPixelSize(R.dimen.bbn_fixed_item_padding_top_inactive); this.paddingBottom = res.getDimensionPixelSize(R.dimen.bbn_fixed_item_padding_bottom); this.paddingHorizontal = res.getDimensionPixelSize(R.dimen.bbn_fixed_item_padding_horizontal); this.textSizeInactive = res.getDimensionPixelSize(R.dimen.bbn_fixed_text_size_inactive); this.iconSize = res.getDimensionPixelSize(R.dimen.bbn_fixed_item_icon_size); this.animationDuration = menu.getItemAnimationDuration(); this.colorActive = menu.getColorActive(); this.colorInactive = menu.getColorInactive(); this.colorDisabled = menu.getColorDisabled(); this.centerY = paddingTopActive; this.canvasTextScale = expanded ? TEXT_SCALE_ACTIVE : 1f; this.iconTranslation = expanded ? 0 : (paddingTopInactive - paddingTopActive); this.textPaint.setColor(Color.WHITE); this.textPaint.setHinting(Paint.HINTING_ON); this.textPaint.setLinearText(true); this.textPaint.setSubpixelText(true); this.textPaint.setTextSize(textSizeInactive); this.textPaint.setColor(expanded ? colorActive : colorInactive); } @Override public void setEnabled(final boolean enabled) { super.setEnabled(enabled); this.textPaint.setColor(isExpanded() ? (enabled ? colorActive : colorDisabled) : (enabled ? colorInactive : colorDisabled)); if (null != icon) { updateLayoutOnAnimation(1, isExpanded()); } requestLayout(); } @Override protected void onStatusChanged(final boolean expanded, final int size, final boolean animate) { if (!animate) { updateLayoutOnAnimation(1, expanded); setIconTranslation(expanded ? 0 : (paddingTopInactive - paddingTopActive)); return; } final AnimatorSet set = new AnimatorSet(); set.setDuration(animationDuration); set.setInterpolator(interpolator); final ValueAnimator animator1 = ObjectAnimator.ofFloat(this, "textScale", expanded ? TEXT_SCALE_ACTIVE : 1); animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(final ValueAnimator animation) { final float fraction = animation.getAnimatedFraction(); updateLayoutOnAnimation(fraction, expanded); } }); final ValueAnimator animator2 = ObjectAnimator.ofFloat(this, "iconTranslation", expanded ? 0 : (paddingTopInactive - paddingTopActive)); set.playTogether(animator1, animator2); set.start(); } private void updateLayoutOnAnimation(final float fraction, final boolean expanded) { final boolean enabled = isEnabled(); final int dstColor = enabled ? (expanded ? colorActive : colorInactive) : colorDisabled; final int srcColor = enabled ? (expanded ? colorInactive : colorActive) : colorDisabled; final int color = (Integer) evaluator.evaluate(fraction, srcColor, dstColor); icon.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); icon.setAlpha(Color.alpha(color)); textPaint.setColor(color); ViewCompat.postInvalidateOnAnimation(this); } @Override protected void onLayout(final boolean changed, final int left, final int top, final int right, final int bottom) { super.onLayout(changed, left, top, right, bottom); if (null == this.icon) { this.icon = getItem().getIcon(getContext()).mutate(); final int color = isExpanded() ? (isEnabled() ? colorActive : colorDisabled) : (isEnabled() ? colorInactive : colorDisabled); this.icon.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); this.icon.setBounds(0, 0, iconSize, iconSize); this.icon.setAlpha(Color.alpha(color)); } if (changed) { int w = right - left; centerX = (w - iconSize) / 2; icon.setBounds(centerX, centerY, centerX + iconSize, centerY + iconSize); } if (textDirty || changed) { measureText(); textDirty = false; } } private void measureText() { final int width = getWidth(); final int height = getHeight(); textWidth = textPaint.measureText(getItem().getTitle()); textX = paddingHorizontal + (((width - paddingHorizontal * 2) - textWidth) / 2); textY = height - paddingBottom; textCenterX = width / 2; textCenterY = height - paddingBottom; } @Override protected void onDraw(final Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(0, iconTranslation); icon.draw(canvas); drawBadge(canvas); canvas.restore(); canvas.save(); canvas.scale(canvasTextScale, canvasTextScale, textCenterX, textCenterY); canvas.drawText( getItem().getTitle(), textX, textY, textPaint ); canvas.restore(); } @SuppressWarnings ("unused") @Keep public int getCenterY() { return centerY; } @SuppressWarnings ("unused") @Keep public void setCenterY(int value) { centerY = value; ViewCompat.postInvalidateOnAnimation(this); } @SuppressWarnings ("unused") @Keep public void setTextScale(final float value) { canvasTextScale = value; ViewCompat.postInvalidateOnAnimation(this); } @SuppressWarnings ("unused") @Keep public float getTextScale() { return canvasTextScale; } @Keep @SuppressWarnings ("unused") public void setIconTranslation(final float iconTranslation) { this.iconTranslation = iconTranslation; ViewCompat.postInvalidateOnAnimation(this); } @Keep @SuppressWarnings ("unused") public float getIconTranslation() { return iconTranslation; } }