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