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