BottomNavigationItemView.java revision 910de28f0a195668fad38ad2367c1f7237a7af98
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.design.internal; 18 19import android.animation.Animator; 20import android.animation.AnimatorSet; 21import android.animation.ValueAnimator; 22import android.annotation.TargetApi; 23import android.content.Context; 24import android.content.res.ColorStateList; 25import android.graphics.drawable.Drawable; 26import android.os.Build; 27import android.support.annotation.NonNull; 28import android.support.design.R; 29import android.support.v4.content.ContextCompat; 30import android.support.v4.graphics.drawable.DrawableCompat; 31import android.support.v4.view.animation.LinearOutSlowInInterpolator; 32import android.support.v7.view.menu.MenuItemImpl; 33import android.support.v7.view.menu.MenuView; 34import android.util.AttributeSet; 35import android.util.TypedValue; 36import android.view.Gravity; 37import android.view.LayoutInflater; 38import android.widget.ImageView; 39import android.widget.TextView; 40 41/** 42 * @hide 43 */ 44public class BottomNavigationItemView extends ForegroundLinearLayout implements MenuView.ItemView { 45 public static final int INVALID_ITEM_POSTION = -1; 46 47 private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked }; 48 private static final long ACTIVE_ANIMATION_DURATION_MS = 115L; 49 50 private final int mHorizontalPadding; 51 private final int mBottomPadding; 52 private final int mTopPadding; 53 private final int mActiveTopPadding; 54 private final float mInactiveLabelSize; 55 private final float mActiveLabelSize; 56 57 private ImageView mIcon; 58 private TextView mLabel; 59 private int mItemPosition = INVALID_ITEM_POSTION; 60 61 private MenuItemImpl mItemData; 62 63 private ColorStateList mIconTint; 64 private ColorStateList mTextColor; 65 66 public BottomNavigationItemView(@NonNull Context context) { 67 this(context, null); 68 } 69 70 public BottomNavigationItemView(@NonNull Context context, AttributeSet attrs) { 71 this(context, attrs, 0); 72 } 73 74 public BottomNavigationItemView(Context context, AttributeSet attrs, int defStyleAttr) { 75 super(context, attrs, defStyleAttr); 76 mHorizontalPadding = getResources().getDimensionPixelSize( 77 R.dimen.design_bottom_navigation_horizontal_padding); 78 mBottomPadding = getResources().getDimensionPixelSize( 79 R.dimen.design_bottom_navigation_bottom_padding); 80 mTopPadding = getResources().getDimensionPixelSize( 81 R.dimen.design_bottom_navigation_top_padding); 82 mActiveTopPadding = getResources().getDimensionPixelSize( 83 R.dimen.design_bottom_navigation_active_top_padding); 84 mInactiveLabelSize = 85 getResources().getDimension(R.dimen.design_bottom_navigation_text_size); 86 mActiveLabelSize = 87 getResources().getDimension(R.dimen.design_bottom_navigation_active_text_size); 88 89 setOrientation(VERTICAL); 90 setGravity(Gravity.CENTER); 91 LayoutInflater.from(context).inflate(R.layout.design_bottom_navigation_item, this, true); 92 setBackgroundResource(R.drawable.design_bottom_navigation_item_background); 93 mIcon = (ImageView) findViewById(R.id.icon); 94 mLabel = (TextView) findViewById(R.id.label); 95 } 96 97 @Override 98 public void initialize(MenuItemImpl itemData, int menuType) { 99 mItemData = itemData; 100 setCheckable(itemData.isCheckable()); 101 setChecked(itemData.isChecked()); 102 setEnabled(itemData.isEnabled()); 103 setIcon(itemData.getIcon()); 104 setTitle(itemData.getTitle()); 105 setId(itemData.getItemId()); 106 } 107 108 public void setItemPosition(int position) { 109 mItemPosition = position; 110 } 111 112 public int getItemPosition() { 113 return mItemPosition; 114 } 115 116 @Override 117 public MenuItemImpl getItemData() { 118 return mItemData; 119 } 120 121 @Override 122 public void setTitle(CharSequence title) { 123 mLabel.setText(title); 124 } 125 126 @Override 127 public void setCheckable(boolean checkable) { 128 refreshDrawableState(); 129 } 130 131 @Override 132 public void setChecked(boolean checked) { 133 mItemData.setChecked(checked); 134 if (checked) { 135 mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mActiveLabelSize); 136 setPadding(mHorizontalPadding, mActiveTopPadding, mHorizontalPadding, mBottomPadding); 137 } else { 138 mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, mInactiveLabelSize); 139 setPadding(mHorizontalPadding, mTopPadding, mHorizontalPadding, mBottomPadding); 140 } 141 refreshDrawableState(); 142 } 143 144 @Override 145 public void setEnabled(boolean enabled) { 146 super.setEnabled(enabled); 147 mLabel.setEnabled(enabled); 148 mIcon.setEnabled(enabled); 149 } 150 151 @Override 152 public int[] onCreateDrawableState(final int extraSpace) { 153 final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 154 if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) { 155 mergeDrawableStates(drawableState, CHECKED_STATE_SET); 156 } 157 return drawableState; 158 } 159 160 @Override 161 public void setShortcut(boolean showShortcut, char shortcutKey) { 162 } 163 164 @Override 165 public void setIcon(Drawable icon) { 166 if (icon != null) { 167 Drawable.ConstantState state = icon.getConstantState(); 168 icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate(); 169 DrawableCompat.setTintList(icon, mIconTint); 170 } 171 mIcon.setImageDrawable(icon); 172 } 173 174 @Override 175 public boolean prefersCondensedTitle() { 176 return false; 177 } 178 179 @Override 180 public boolean showsIcon() { 181 return true; 182 } 183 184 public void setIconTintList(ColorStateList tint) { 185 mIconTint = tint; 186 if (mItemData != null) { 187 // Update the icon so that the tint takes effect 188 setIcon(mItemData.getIcon()); 189 } 190 } 191 192 public void setTextColor(ColorStateList color) { 193 mTextColor = color; 194 mLabel.setTextColor(color); 195 } 196 197 public void setItemBackground(int background) { 198 Drawable backgroundDrawable = background == 0 199 ? null : ContextCompat.getDrawable(getContext(), background); 200 setBackgroundDrawable(backgroundDrawable); 201 } 202 203 @TargetApi(Build.VERSION_CODES.HONEYCOMB) 204 public Animator getAnimator(boolean active) { 205 final float currentTextSize = mLabel.getTextSize(); 206 final int currentTopPadding = getPaddingTop(); 207 208 final float finalTextSize = active ? mActiveLabelSize : mInactiveLabelSize; 209 final int finalTopPadding = active ? mActiveTopPadding : mTopPadding; 210 211 if (currentTextSize == finalTextSize && currentTopPadding == finalTopPadding) { 212 return null; 213 } 214 215 // Grow or shrink the text of the tab. 216 ValueAnimator textAnimator = ValueAnimator.ofFloat(currentTextSize, finalTextSize); 217 textAnimator.setDuration(ACTIVE_ANIMATION_DURATION_MS); 218 textAnimator.setInterpolator(new LinearOutSlowInInterpolator()); 219 textAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 220 @Override 221 public void onAnimationUpdate(ValueAnimator valueAnimator) { 222 float animatedValue = (float) valueAnimator.getAnimatedValue(); 223 mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, animatedValue); 224 } 225 }); 226 227 // Reduce or increase the padding top of the tab. 228 ValueAnimator paddingTopAnimator = ValueAnimator.ofInt(currentTopPadding, finalTopPadding); 229 paddingTopAnimator.setDuration(ACTIVE_ANIMATION_DURATION_MS); 230 paddingTopAnimator.setInterpolator(new LinearOutSlowInInterpolator()); 231 paddingTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 232 @Override 233 public void onAnimationUpdate(ValueAnimator valueAnimator) { 234 int animatedValue = (int) valueAnimator.getAnimatedValue(); 235 setPadding(mHorizontalPadding, animatedValue, 236 mHorizontalPadding, mBottomPadding); 237 } 238 }); 239 240 AnimatorSet set = new AnimatorSet(); 241 set.playTogether(textAnimator, paddingTopAnimator); 242 return set; 243 } 244} 245