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