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