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