BottomNavigationItemView.java revision 69557a3a037e4124ecbc98560e84fa89472b3bf4
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 static android.support.annotation.RestrictTo.Scope.GROUP_ID; 20 21import android.content.Context; 22import android.content.res.ColorStateList; 23import android.content.res.Resources; 24import android.graphics.drawable.Drawable; 25import android.support.annotation.NonNull; 26import android.support.annotation.RestrictTo; 27import android.support.design.R; 28import android.support.v4.content.ContextCompat; 29import android.support.v4.graphics.drawable.DrawableCompat; 30import android.support.v4.view.ViewCompat; 31import android.support.v7.view.menu.MenuItemImpl; 32import android.support.v7.view.menu.MenuView; 33import android.util.AttributeSet; 34import android.view.Gravity; 35import android.view.LayoutInflater; 36import android.widget.FrameLayout; 37import android.widget.ImageView; 38import android.widget.TextView; 39 40/** 41 * @hide 42 */ 43@RestrictTo(GROUP_ID) 44public class BottomNavigationItemView extends FrameLayout implements MenuView.ItemView { 45 public static final int INVALID_ITEM_POSITION = -1; 46 47 private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked }; 48 49 private final int mDefaultMargin; 50 private final int mShiftAmount; 51 private final float mScaleUpFactor; 52 private final float mScaleDownFactor; 53 54 private boolean mShiftingMode; 55 56 private ImageView mIcon; 57 private final TextView mSmallLabel; 58 private final TextView mLargeLabel; 59 private int mItemPosition = INVALID_ITEM_POSITION; 60 61 private MenuItemImpl mItemData; 62 63 private ColorStateList mIconTint; 64 65 public BottomNavigationItemView(@NonNull Context context) { 66 this(context, null); 67 } 68 69 public BottomNavigationItemView(@NonNull Context context, AttributeSet attrs) { 70 this(context, attrs, 0); 71 } 72 73 public BottomNavigationItemView(Context context, AttributeSet attrs, int defStyleAttr) { 74 super(context, attrs, defStyleAttr); 75 final Resources res = getResources(); 76 int inactiveLabelSize = 77 res.getDimensionPixelSize(R.dimen.design_bottom_navigation_text_size); 78 int activeLabelSize = res.getDimensionPixelSize( 79 R.dimen.design_bottom_navigation_active_text_size); 80 mDefaultMargin = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_margin); 81 mShiftAmount = inactiveLabelSize - activeLabelSize; 82 mScaleUpFactor = 1f * activeLabelSize / inactiveLabelSize; 83 mScaleDownFactor = 1f * inactiveLabelSize / activeLabelSize; 84 85 LayoutInflater.from(context).inflate(R.layout.design_bottom_navigation_item, this, true); 86 setBackgroundResource(R.drawable.design_bottom_navigation_item_background); 87 mIcon = (ImageView) findViewById(R.id.icon); 88 mSmallLabel = (TextView) findViewById(R.id.smallLabel); 89 mLargeLabel = (TextView) findViewById(R.id.largeLabel); 90 91 } 92 93 @Override 94 public void initialize(MenuItemImpl itemData, int menuType) { 95 mItemData = itemData; 96 setCheckable(itemData.isCheckable()); 97 setChecked(itemData.isChecked()); 98 setEnabled(itemData.isEnabled()); 99 setIcon(itemData.getIcon()); 100 setTitle(itemData.getTitle()); 101 setId(itemData.getItemId()); 102 } 103 104 public void setItemPosition(int position) { 105 mItemPosition = position; 106 } 107 108 public int getItemPosition() { 109 return mItemPosition; 110 } 111 112 public void setShiftingMode(boolean enabled) { 113 mShiftingMode = enabled; 114 } 115 116 @Override 117 public MenuItemImpl getItemData() { 118 return mItemData; 119 } 120 121 @Override 122 public void setTitle(CharSequence title) { 123 mSmallLabel.setText(title); 124 mLargeLabel.setText(title); 125 } 126 127 @Override 128 public void setCheckable(boolean checkable) { 129 refreshDrawableState(); 130 } 131 132 @Override 133 public void setChecked(boolean checked) { 134 ViewCompat.setPivotX(mLargeLabel, mLargeLabel.getWidth() / 2); 135 ViewCompat.setPivotY(mLargeLabel, mLargeLabel.getBaseline()); 136 ViewCompat.setPivotX(mSmallLabel, mSmallLabel.getWidth() / 2); 137 ViewCompat.setPivotY(mSmallLabel, mSmallLabel.getBaseline()); 138 if (mShiftingMode) { 139 if (checked) { 140 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams(); 141 iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; 142 iconParams.topMargin = mDefaultMargin; 143 mIcon.setLayoutParams(iconParams); 144 mLargeLabel.setVisibility(VISIBLE); 145 ViewCompat.setScaleX(mLargeLabel, 1f); 146 ViewCompat.setScaleY(mLargeLabel, 1f); 147 } else { 148 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams(); 149 iconParams.gravity = Gravity.CENTER; 150 iconParams.topMargin = mDefaultMargin; 151 mIcon.setLayoutParams(iconParams); 152 mLargeLabel.setVisibility(INVISIBLE); 153 ViewCompat.setScaleX(mLargeLabel, 0.5f); 154 ViewCompat.setScaleY(mLargeLabel, 0.5f); 155 } 156 mSmallLabel.setVisibility(INVISIBLE); 157 } else { 158 if (checked) { 159 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams(); 160 iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; 161 iconParams.topMargin = mDefaultMargin + mShiftAmount; 162 mIcon.setLayoutParams(iconParams); 163 mLargeLabel.setVisibility(VISIBLE); 164 mSmallLabel.setVisibility(INVISIBLE); 165 166 ViewCompat.setScaleX(mLargeLabel, 1f); 167 ViewCompat.setScaleY(mLargeLabel, 1f); 168 ViewCompat.setScaleX(mSmallLabel, mScaleUpFactor); 169 ViewCompat.setScaleY(mSmallLabel, mScaleUpFactor); 170 } else { 171 LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams(); 172 iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; 173 iconParams.topMargin = mDefaultMargin; 174 mIcon.setLayoutParams(iconParams); 175 mLargeLabel.setVisibility(INVISIBLE); 176 mSmallLabel.setVisibility(VISIBLE); 177 178 ViewCompat.setScaleX(mLargeLabel, mScaleDownFactor); 179 ViewCompat.setScaleY(mLargeLabel, mScaleDownFactor); 180 ViewCompat.setScaleX(mSmallLabel, 1f); 181 ViewCompat.setScaleY(mSmallLabel, 1f); 182 } 183 } 184 185 refreshDrawableState(); 186 } 187 188 @Override 189 public void setEnabled(boolean enabled) { 190 super.setEnabled(enabled); 191 mSmallLabel.setEnabled(enabled); 192 mLargeLabel.setEnabled(enabled); 193 mIcon.setEnabled(enabled); 194 } 195 196 @Override 197 public int[] onCreateDrawableState(final int extraSpace) { 198 final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 199 if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) { 200 mergeDrawableStates(drawableState, CHECKED_STATE_SET); 201 } 202 return drawableState; 203 } 204 205 @Override 206 public void setShortcut(boolean showShortcut, char shortcutKey) { 207 } 208 209 @Override 210 public void setIcon(Drawable icon) { 211 if (icon != null) { 212 Drawable.ConstantState state = icon.getConstantState(); 213 icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate(); 214 DrawableCompat.setTintList(icon, mIconTint); 215 } 216 mIcon.setImageDrawable(icon); 217 } 218 219 @Override 220 public boolean prefersCondensedTitle() { 221 return false; 222 } 223 224 @Override 225 public boolean showsIcon() { 226 return true; 227 } 228 229 public void setIconTintList(ColorStateList tint) { 230 mIconTint = tint; 231 if (mItemData != null) { 232 // Update the icon so that the tint takes effect 233 setIcon(mItemData.getIcon()); 234 } 235 } 236 237 public void setTextColor(ColorStateList color) { 238 mSmallLabel.setTextColor(color); 239 mLargeLabel.setTextColor(color); 240 } 241 242 public void setItemBackground(int background) { 243 Drawable backgroundDrawable = background == 0 244 ? null : ContextCompat.getDrawable(getContext(), background); 245 ViewCompat.setBackground(this, backgroundDrawable); 246 } 247} 248