NavigationMenuItemView.java revision a4c6825b4b077cb12adb4f14b825001b6fd0e865
1/* 2 * Copyright (C) 2015 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.graphics.Color; 24import android.graphics.drawable.ColorDrawable; 25import android.graphics.drawable.Drawable; 26import android.graphics.drawable.StateListDrawable; 27import android.support.annotation.RestrictTo; 28import android.support.design.R; 29import android.support.v4.content.res.ResourcesCompat; 30import android.support.v4.graphics.drawable.DrawableCompat; 31import android.support.v4.view.AccessibilityDelegateCompat; 32import android.support.v4.view.ViewCompat; 33import android.support.v4.view.accessibility.AccessibilityEventCompat; 34import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 35import android.support.v4.widget.TextViewCompat; 36import android.support.v7.view.menu.MenuItemImpl; 37import android.support.v7.view.menu.MenuView; 38import android.support.v7.widget.TooltipCompat; 39import android.util.AttributeSet; 40import android.util.TypedValue; 41import android.view.LayoutInflater; 42import android.view.View; 43import android.view.ViewStub; 44import android.widget.CheckedTextView; 45import android.widget.FrameLayout; 46 47/** 48 * @hide 49 */ 50@RestrictTo(LIBRARY_GROUP) 51public class NavigationMenuItemView extends ForegroundLinearLayout implements MenuView.ItemView { 52 53 private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked}; 54 55 private final int mIconSize; 56 57 private boolean mNeedsEmptyIcon; 58 59 boolean mCheckable; 60 61 private final CheckedTextView mTextView; 62 63 private FrameLayout mActionArea; 64 65 private MenuItemImpl mItemData; 66 67 private ColorStateList mIconTintList; 68 69 private boolean mHasIconTintList; 70 71 private Drawable mEmptyDrawable; 72 73 private final AccessibilityDelegateCompat mAccessibilityDelegate 74 = new AccessibilityDelegateCompat() { 75 76 @Override 77 public void onInitializeAccessibilityNodeInfo(View host, 78 AccessibilityNodeInfoCompat info) { 79 super.onInitializeAccessibilityNodeInfo(host, info); 80 info.setCheckable(mCheckable); 81 } 82 83 }; 84 85 public NavigationMenuItemView(Context context) { 86 this(context, null); 87 } 88 89 public NavigationMenuItemView(Context context, AttributeSet attrs) { 90 this(context, attrs, 0); 91 } 92 93 public NavigationMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) { 94 super(context, attrs, defStyleAttr); 95 setOrientation(HORIZONTAL); 96 LayoutInflater.from(context).inflate(R.layout.design_navigation_menu_item, this, true); 97 mIconSize = context.getResources().getDimensionPixelSize( 98 R.dimen.design_navigation_icon_size); 99 mTextView = (CheckedTextView) findViewById(R.id.design_menu_item_text); 100 mTextView.setDuplicateParentStateEnabled(true); 101 ViewCompat.setAccessibilityDelegate(mTextView, mAccessibilityDelegate); 102 } 103 104 @Override 105 public void initialize(MenuItemImpl itemData, int menuType) { 106 mItemData = itemData; 107 108 setVisibility(itemData.isVisible() ? VISIBLE : GONE); 109 110 if (getBackground() == null) { 111 ViewCompat.setBackground(this, createDefaultBackground()); 112 } 113 114 setCheckable(itemData.isCheckable()); 115 setChecked(itemData.isChecked()); 116 setEnabled(itemData.isEnabled()); 117 setTitle(itemData.getTitle()); 118 setIcon(itemData.getIcon()); 119 setActionView(itemData.getActionView()); 120 setContentDescription(itemData.getContentDescription()); 121 TooltipCompat.setTooltipText(this, itemData.getTooltipText()); 122 adjustAppearance(); 123 } 124 125 private boolean shouldExpandActionArea() { 126 return mItemData.getTitle() == null && 127 mItemData.getIcon() == null && 128 mItemData.getActionView() != null; 129 } 130 131 private void adjustAppearance() { 132 if (shouldExpandActionArea()) { 133 // Expand the actionView area 134 mTextView.setVisibility(View.GONE); 135 if (mActionArea != null) { 136 LayoutParams params = (LayoutParams) mActionArea.getLayoutParams(); 137 params.width = LayoutParams.MATCH_PARENT; 138 mActionArea.setLayoutParams(params); 139 } 140 } else { 141 mTextView.setVisibility(View.VISIBLE); 142 if (mActionArea != null) { 143 LayoutParams params = (LayoutParams) mActionArea.getLayoutParams(); 144 params.width = LayoutParams.WRAP_CONTENT; 145 mActionArea.setLayoutParams(params); 146 } 147 } 148 } 149 150 public void recycle() { 151 if (mActionArea != null) { 152 mActionArea.removeAllViews(); 153 } 154 mTextView.setCompoundDrawables(null, null, null, null); 155 } 156 157 private void setActionView(View actionView) { 158 if (actionView != null) { 159 if (mActionArea == null) { 160 mActionArea = (FrameLayout) ((ViewStub) findViewById( 161 R.id.design_menu_item_action_area_stub)).inflate(); 162 } 163 mActionArea.removeAllViews(); 164 mActionArea.addView(actionView); 165 } 166 } 167 168 private StateListDrawable createDefaultBackground() { 169 TypedValue value = new TypedValue(); 170 if (getContext().getTheme().resolveAttribute( 171 android.support.v7.appcompat.R.attr.colorControlHighlight, value, true)) { 172 StateListDrawable drawable = new StateListDrawable(); 173 drawable.addState(CHECKED_STATE_SET, new ColorDrawable(value.data)); 174 drawable.addState(EMPTY_STATE_SET, new ColorDrawable(Color.TRANSPARENT)); 175 return drawable; 176 } 177 return null; 178 } 179 180 @Override 181 public MenuItemImpl getItemData() { 182 return mItemData; 183 } 184 185 @Override 186 public void setTitle(CharSequence title) { 187 mTextView.setText(title); 188 } 189 190 @Override 191 public void setCheckable(boolean checkable) { 192 refreshDrawableState(); 193 if (mCheckable != checkable) { 194 mCheckable = checkable; 195 mAccessibilityDelegate.sendAccessibilityEvent(mTextView, 196 AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); 197 } 198 } 199 200 @Override 201 public void setChecked(boolean checked) { 202 refreshDrawableState(); 203 mTextView.setChecked(checked); 204 } 205 206 @Override 207 public void setShortcut(boolean showShortcut, char shortcutKey) { 208 } 209 210 @Override 211 public void setIcon(Drawable icon) { 212 if (icon != null) { 213 if (mHasIconTintList) { 214 Drawable.ConstantState state = icon.getConstantState(); 215 icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate(); 216 DrawableCompat.setTintList(icon, mIconTintList); 217 } 218 icon.setBounds(0, 0, mIconSize, mIconSize); 219 } else if (mNeedsEmptyIcon) { 220 if (mEmptyDrawable == null) { 221 mEmptyDrawable = ResourcesCompat.getDrawable(getResources(), 222 R.drawable.navigation_empty_icon, getContext().getTheme()); 223 if (mEmptyDrawable != null) { 224 mEmptyDrawable.setBounds(0, 0, mIconSize, mIconSize); 225 } 226 } 227 icon = mEmptyDrawable; 228 } 229 TextViewCompat.setCompoundDrawablesRelative(mTextView, icon, null, null, null); 230 } 231 232 @Override 233 public boolean prefersCondensedTitle() { 234 return false; 235 } 236 237 @Override 238 public boolean showsIcon() { 239 return true; 240 } 241 242 @Override 243 protected int[] onCreateDrawableState(int extraSpace) { 244 final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 245 if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) { 246 mergeDrawableStates(drawableState, CHECKED_STATE_SET); 247 } 248 return drawableState; 249 } 250 251 void setIconTintList(ColorStateList tintList) { 252 mIconTintList = tintList; 253 mHasIconTintList = mIconTintList != null; 254 if (mItemData != null) { 255 // Update the icon so that the tint takes effect 256 setIcon(mItemData.getIcon()); 257 } 258 } 259 260 public void setTextAppearance(int textAppearance) { 261 TextViewCompat.setTextAppearance(mTextView, textAppearance); 262 } 263 264 public void setTextColor(ColorStateList colors) { 265 mTextView.setTextColor(colors); 266 } 267 268 public void setNeedsEmptyIcon(boolean needsEmptyIcon) { 269 mNeedsEmptyIcon = needsEmptyIcon; 270 } 271 272} 273