BottomNavigationMenuView.java revision 23e274886774bf1a6c433ed98503e148fa1e15b4
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 android.animation.AnimatorSet; 20import android.content.Context; 21import android.content.res.ColorStateList; 22import android.os.Build; 23import android.support.annotation.Nullable; 24import android.support.design.R; 25import android.support.v4.util.Pools; 26import android.support.v7.view.menu.MenuBuilder; 27import android.support.v7.view.menu.MenuItemImpl; 28import android.support.v7.view.menu.MenuView; 29import android.util.AttributeSet; 30import android.view.Gravity; 31import android.view.View; 32import android.view.ViewGroup; 33import android.widget.LinearLayout; 34 35/** 36 * @hide 37 */ 38public class BottomNavigationMenuView extends LinearLayout implements MenuView { 39 private final int mInactiveItemMaxWidth; 40 private final int mActiveItemMaxWidth; 41 private final OnClickListener mOnClickListener; 42 private static final Pools.Pool<BottomNavigationItemView> sItemPool = 43 new Pools.SynchronizedPool<>(5); 44 45 private BottomNavigationItemView[] mButtons; 46 private int mActiveButton = 0; 47 private ColorStateList mItemIconTint; 48 private ColorStateList mItemTextColor; 49 private int mItemBackgroundRes; 50 51 private BottomNavigationPresenter mPresenter; 52 private MenuBuilder mMenu; 53 54 public BottomNavigationMenuView(Context context) { 55 this(context, null); 56 } 57 58 public BottomNavigationMenuView(Context context, AttributeSet attrs) { 59 this(context, attrs, 0); 60 } 61 62 public BottomNavigationMenuView(Context context, AttributeSet attrs, int defStyleAttr) { 63 super(context, attrs, defStyleAttr); 64 setGravity(Gravity.CENTER); 65 setOrientation(HORIZONTAL); 66 67 mInactiveItemMaxWidth = getResources().getDimensionPixelSize( 68 R.dimen.design_bottom_navigation_item_max_width); 69 mActiveItemMaxWidth = getResources() 70 .getDimensionPixelSize(R.dimen.design_bottom_navigation_active_item_max_width); 71 72 mOnClickListener = new OnClickListener() { 73 @Override 74 public void onClick(View v) { 75 final int itemPosition = ((BottomNavigationItemView) v).getItemPosition(); 76 activateNewButton(itemPosition); 77 } 78 }; 79 } 80 81 @Override 82 public void initialize(MenuBuilder menu) { 83 mMenu = menu; 84 if (mMenu == null) return; 85 if (mMenu.size() > mActiveButton) { 86 mMenu.getItem(mActiveButton).setChecked(true); 87 } 88 } 89 90 @Override 91 public int getWindowAnimations() { 92 return 0; 93 } 94 95 public void setIconTintList(ColorStateList color) { 96 mItemIconTint = color; 97 if (mButtons == null) return; 98 for (BottomNavigationItemView item : mButtons) { 99 item.setIconTintList(color); 100 } 101 } 102 103 @Nullable 104 public ColorStateList getIconTintList() { 105 return mItemIconTint; 106 } 107 108 public void setItemTextColor(ColorStateList color) { 109 mItemTextColor = color; 110 if (mButtons == null) return; 111 for (BottomNavigationItemView item : mButtons) { 112 item.setTextColor(color); 113 } 114 } 115 116 public ColorStateList getItemTextColor() { 117 return mItemTextColor; 118 } 119 120 public void setItemBackgroundRes(int background) { 121 mItemBackgroundRes = background; 122 if (mButtons == null) return; 123 for (BottomNavigationItemView item : mButtons) { 124 item.setItemBackground(background); 125 } 126 } 127 128 public int getItemBackgroundRes() { 129 return mItemBackgroundRes; 130 } 131 132 public void setPresenter(BottomNavigationPresenter presenter) { 133 mPresenter = presenter; 134 } 135 136 public void buildMenuView() { 137 if (mButtons != null) { 138 for (BottomNavigationItemView item : mButtons) { 139 sItemPool.release(item); 140 } 141 } 142 removeAllViews(); 143 mButtons = new BottomNavigationItemView[mMenu.size()]; 144 for (int i = 0; i < mMenu.size(); i++) { 145 mPresenter.setUpdateSuspended(true); 146 mMenu.getItem(i).setCheckable(true); 147 mPresenter.setUpdateSuspended(false); 148 BottomNavigationItemView child = getNewItem(); 149 mButtons[i] = child; 150 child.setIconTintList(mItemIconTint); 151 child.setTextColor(mItemTextColor); 152 child.setItemBackground(mItemBackgroundRes); 153 child.initialize((MenuItemImpl) mMenu.getItem(i), 0); 154 child.setItemPosition(i); 155 child.setOnClickListener(mOnClickListener); 156 addView(child); 157 } 158 } 159 160 public void updateMenuView() { 161 final int menuSize = mMenu.size(); 162 if (menuSize != mButtons.length) { 163 // The size has changed. Rebuild menu view from scratch. 164 buildMenuView(); 165 return; 166 } 167 for (int i = 0; i < menuSize; i++) { 168 mPresenter.setUpdateSuspended(true); 169 mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0); 170 mPresenter.setUpdateSuspended(false); 171 } 172 } 173 174 private void activateNewButton(int newButton) { 175 if (mActiveButton == newButton) return; 176 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 177 AnimatorSet animatorSet = new AnimatorSet(); 178 animatorSet.playTogether( 179 mButtons[mActiveButton].getAnimator(false), 180 mButtons[newButton].getAnimator(true)); 181 animatorSet.start(); 182 } 183 mPresenter.setUpdateSuspended(true); 184 mButtons[mActiveButton].setChecked(false); 185 mButtons[newButton].setChecked(true); 186 mPresenter.setUpdateSuspended(false); 187 188 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 189 // Manually force UI update since we cannot use animations. 190 mPresenter.updateMenuView(true); 191 } 192 mActiveButton = newButton; 193 } 194 195 public void updateOnSizeChange(int width) { 196 if (getChildCount() == 0) return; 197 int available = width / getChildCount(); 198 int itemWidth = Math.min(available, mActiveItemMaxWidth); 199 200 for (int i = 0; i < mButtons.length; i++) { 201 ViewGroup.LayoutParams params = mButtons[i].getLayoutParams(); 202 if (params.width == itemWidth) { 203 continue; 204 } 205 params.width = itemWidth; 206 params.height = ViewGroup.LayoutParams.MATCH_PARENT; 207 mButtons[i].setLayoutParams(params); 208 } 209 } 210 211 private BottomNavigationItemView getNewItem() { 212 BottomNavigationItemView item = sItemPool.acquire(); 213 if (item == null) { 214 item = new BottomNavigationItemView(getContext()); 215 } 216 return item; 217 } 218} 219