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