ScrollingTabContainerView.java revision 64dbe1d454f1190b3cd8426d09b9119949a10709
1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/* 2bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Copyright (C) 2011 The Android Open Source Project 3bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 4bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * you may not use this file except in compliance with the License. 6bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * You may obtain a copy of the License at 7bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 8bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * http://www.apache.org/licenses/LICENSE-2.0 9bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 10bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Unless required by applicable law or agreed to in writing, software 11bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * See the License for the specific language governing permissions and 14bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * limitations under the License. 15bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 1666698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banespackage android.support.v7.widget; 17bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context; 19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.res.Configuration; 20bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.graphics.drawable.Drawable; 2149c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.os.Build; 2249c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.GravityCompat; 2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewCompat; 2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorCompat; 2549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorListener; 26da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.app.ActionBar; 27da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R; 2866698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.ActionBarPolicy; 2949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.text.TextUtils; 30bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.text.TextUtils.TruncateAt; 31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.Gravity; 32bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View; 33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewGroup; 34bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewParent; 3549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.accessibility.AccessibilityEvent; 3649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.accessibility.AccessibilityNodeInfo; 3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.animation.DecelerateInterpolator; 3849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.animation.Interpolator; 39f933672168f6deff5e3636584bec735416b5a93bChris Banesimport android.widget.AdapterView; 40bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.BaseAdapter; 41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.HorizontalScrollView; 42bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ImageView; 43bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ListView; 44f933672168f6deff5e3636584bec735416b5a93bChris Banesimport android.widget.Spinner; 45bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.TextView; 4649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.Toast; 47bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 48bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 4920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * This widget implements the dynamic action bar tab behavior that can change across different 5020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * configurations or circumstances. 5189208232f3b5d1451408d787872504a190bc7ee0Chris Banes * 5289208232f3b5d1451408d787872504a190bc7ee0Chris Banes * @hide 53bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 54bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellpublic class ScrollingTabContainerView extends HorizontalScrollView 55f933672168f6deff5e3636584bec735416b5a93bChris Banes implements AdapterView.OnItemSelectedListener { 5620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 57ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private static final String TAG = "ScrollingTabContainerView"; 58ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani Runnable mTabSelector; 59ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TabClickListener mTabClickListener; 60bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 6149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private LinearLayoutCompat mTabLayout; 62f933672168f6deff5e3636584bec735416b5a93bChris Banes private Spinner mTabSpinner; 63ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean mAllowCollapse; 64bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 65ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani int mMaxTabWidth; 66ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani int mStackedTabMaxWidth; 67ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mContentHeight; 68ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mSelectedTabIndex; 69bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 7049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected ViewPropertyAnimatorCompat mVisibilityAnim; 7149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); 7249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final Interpolator sAlphaInterpolator = new DecelerateInterpolator(); 7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final int FADE_DURATION = 200; 7649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 77ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ScrollingTabContainerView(Context context) { 78ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super(context); 79624d7ed5e2d6dc7a937468dda7bef1f65cd765d7Chris Banes 80ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setHorizontalScrollBarEnabled(false); 81bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 82ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ActionBarPolicy abp = ActionBarPolicy.get(context); 83ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setContentHeight(abp.getTabContainerHeight()); 84ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); 85bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 8649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout = createTabLayout(); 87ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 8849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.MATCH_PARENT)); 89bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 90ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 91ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 92ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 93ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 94ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY; 95ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setFillViewport(lockedExpanded); 96ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 97ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int childCount = mTabLayout.getChildCount(); 98ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (childCount > 1 && 9920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) { 100ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (childCount > 2) { 101ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f); 102ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 103ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2; 104ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 105ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = Math.min(mMaxTabWidth, mStackedTabMaxWidth); 106ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 107ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = -1; 108ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 109ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY); 111ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 112ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean canCollapse = !lockedExpanded && mAllowCollapse; 113ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 114ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (canCollapse) { 115ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // See if we should expand 116ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec); 117ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) { 118ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani performCollapse(); 119ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 120ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani performExpand(); 121ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 122ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 123ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani performExpand(); 124ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 125ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 126ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int oldWidth = getMeasuredWidth(); 127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 128ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int newWidth = getMeasuredWidth(); 129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (lockedExpanded && oldWidth != newWidth) { 131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Recenter the tab display if we're at a new (scrollable) size. 132ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setTabSelected(mSelectedTabIndex); 133ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 134bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 135ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani /** 13749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Indicates whether this view is collapsed into a dropdown menu instead 13849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * of traditional tabs. 139ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani * @return true if showing as a spinner 140ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani */ 141ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean isCollapsed() { 142ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTabSpinner != null && mTabSpinner.getParent() == this; 143bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 144ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 145ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setAllowCollapse(boolean allowCollapse) { 146ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mAllowCollapse = allowCollapse; 147bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 148ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 149ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private void performCollapse() { 15049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (isCollapsed()) return; 151ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 152ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner == null) { 153ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSpinner = createSpinner(); 154ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 155ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mTabLayout); 156ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 15749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.MATCH_PARENT)); 158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner.getAdapter() == null) { 159ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSpinner.setAdapter(new TabAdapter()); 160ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 161ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 162ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = null; 164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSpinner.setSelection(mSelectedTabIndex); 166bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 168ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean performExpand() { 16949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!isCollapsed()) return false; 170ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 171ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mTabSpinner); 172ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 17349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.MATCH_PARENT)); 174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setTabSelected(mTabSpinner.getSelectedItemPosition()); 175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 176bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 177ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 178ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setTabSelected(int position) { 179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mSelectedTabIndex = position; 180ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int tabCount = mTabLayout.getChildCount(); 181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < tabCount; i++) { 182ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View child = mTabLayout.getChildAt(i); 183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean isSelected = i == position; 184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani child.setSelected(isSelected); 185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (isSelected) { 186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani animateToTab(position); 187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 189b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes if (mTabSpinner != null && position >= 0) { 190b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes mTabSpinner.setSelection(position); 191b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes } 192bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 193bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 194ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setContentHeight(int contentHeight) { 195ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mContentHeight = contentHeight; 196ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 197bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 198ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 19949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private LinearLayoutCompat createTabLayout() { 20049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final LinearLayoutCompat tabLayout = new LinearLayoutCompat(getContext(), null, 20149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes R.attr.actionBarTabBarStyle); 20249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabLayout.setMeasureWithLargestChildEnabled(true); 20349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabLayout.setGravity(Gravity.CENTER); 20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabLayout.setLayoutParams(new LinearLayoutCompat.LayoutParams( 20549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.MATCH_PARENT)); 20649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return tabLayout; 20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 209f933672168f6deff5e3636584bec735416b5a93bChris Banes private Spinner createSpinner() { 210f933672168f6deff5e3636584bec735416b5a93bChris Banes final Spinner spinner = new AppCompatSpinner(getContext(), null, 21120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.attr.actionDropDownStyle); 21249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes spinner.setLayoutParams(new LinearLayoutCompat.LayoutParams( 213f933672168f6deff5e3636584bec735416b5a93bChris Banes LinearLayoutCompat.LayoutParams.WRAP_CONTENT, 214f933672168f6deff5e3636584bec735416b5a93bChris Banes LinearLayoutCompat.LayoutParams.MATCH_PARENT)); 215f933672168f6deff5e3636584bec735416b5a93bChris Banes spinner.setOnItemSelectedListener(this); 216ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return spinner; 217bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 218ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 219ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani protected void onConfigurationChanged(Configuration newConfig) { 22064dbe1d454f1190b3cd8426d09b9119949a10709Kirill Grouchnikov super.onConfigurationChanged(newConfig); 22149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 222ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ActionBarPolicy abp = ActionBarPolicy.get(getContext()); 223ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Action bar can change size on configuration changes. 224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Reread the desired height from the theme-specified style. 225ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setContentHeight(abp.getTabContainerHeight()); 226ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); 227bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 228ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 22949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void animateToVisibility(int visibility) { 23049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mVisibilityAnim != null) { 23149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim.cancel(); 23249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 23349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (visibility == VISIBLE) { 23449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (getVisibility() != VISIBLE) { 23549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewCompat.setAlpha(this, 0f); 23649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 23749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 23849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f); 23949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setDuration(FADE_DURATION); 24049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setInterpolator(sAlphaInterpolator); 24249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); 24349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.start(); 24449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 24549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f); 24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setDuration(FADE_DURATION); 24749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setInterpolator(sAlphaInterpolator); 24949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); 25049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.start(); 25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 25249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 25349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 254ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void animateToTab(final int position) { 255ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View tabView = mTabLayout.getChildAt(position); 256ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 257ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 258ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = new Runnable() { 260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void run() { 261ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2; 262ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani smoothScrollTo(scrollPos, 0); 263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = null; 264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 265ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani }; 266ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani post(mTabSelector); 267bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 268ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 269ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onAttachedToWindow() { 271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onAttachedToWindow(); 272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 273ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Re-post the selector we saved 274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani post(mTabSelector); 275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 276bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onDetachedFromWindow() { 280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onDetachedFromWindow(); 281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 284bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) { 28749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final TabView tabView = new TabView(getContext(), tab, forAdapter); 288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (forAdapter) { 289ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setBackgroundDrawable(null); 29049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, 29120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mContentHeight)); 292ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 293ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setFocusable(true); 294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabClickListener == null) { 296ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabClickListener = new TabClickListener(); 297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 298ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setOnClickListener(mTabClickListener); 299ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 300ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return tabView; 301bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 302bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 303ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void addTab(ActionBar.Tab tab, boolean setSelected) { 304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = createTabView(tab, false); 30549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout.addView(tabView, new LinearLayoutCompat.LayoutParams(0, 30649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes LayoutParams.MATCH_PARENT, 1)); 307ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 308ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 310ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (setSelected) { 311ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setSelected(true); 312ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 316bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 318ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { 319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final TabView tabView = createTabView(tab, false); 32049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout.addView(tabView, position, new LinearLayoutCompat.LayoutParams( 32149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 0, LayoutParams.MATCH_PARENT, 1)); 322ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 323ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (setSelected) { 326ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setSelected(true); 327ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 331bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 332bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 333ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void updateTab(int position) { 334ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabView) mTabLayout.getChildAt(position)).update(); 335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 337ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 338ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 339ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 341bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 343ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void removeTabAt(int position) { 344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.removeViewAt(position); 345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 346ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 347ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 348ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 350ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 351bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 352bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 353ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void removeAllTabs() { 354ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.removeAllViews(); 355ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 357ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 358ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 359ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 361bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 363ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 364f933672168f6deff5e3636584bec735416b5a93bChris Banes public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { 365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = (TabView) view; 366ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.getTab().select(); 367bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 368bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 369f933672168f6deff5e3636584bec735416b5a93bChris Banes @Override 370f933672168f6deff5e3636584bec735416b5a93bChris Banes public void onNothingSelected(AdapterView<?> adapterView) { 371f933672168f6deff5e3636584bec735416b5a93bChris Banes // no-op 372f933672168f6deff5e3636584bec735416b5a93bChris Banes } 373f933672168f6deff5e3636584bec735416b5a93bChris Banes 37449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private class TabView extends LinearLayoutCompat implements OnLongClickListener { 375469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private final int[] BG_ATTRS = { 376469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes android.R.attr.background 377469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 378469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 379ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ActionBar.Tab mTab; 380ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TextView mTextView; 381ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ImageView mIconView; 382ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private View mCustomView; 383bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 38449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public TabView(Context context, ActionBar.Tab tab, boolean forList) { 38549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(context, null, R.attr.actionBarTabStyle); 386ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTab = tab; 38734b5c9580dd01b4428ab2c5990add571eaab6b13Trevor Johns 388469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, null, BG_ATTRS, 389469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.attr.actionBarTabStyle, 0); 390469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (a.hasValue(0)) { 391469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes setBackgroundDrawable(a.getDrawable(0)); 392469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 393469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes a.recycle(); 394469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 395ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (forList) { 39649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setGravity(GravityCompat.START | Gravity.CENTER_VERTICAL); 397ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 398bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 399ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani update(); 400ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 401bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 402ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void bindTab(ActionBar.Tab tab) { 403ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTab = tab; 404ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani update(); 405ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 406bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 407ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 40849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setSelected(boolean selected) { 40949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean changed = (isSelected() != selected); 41049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.setSelected(selected); 41149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (changed && selected) { 41249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 41349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 41449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 41549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 41649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 41749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 41849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onInitializeAccessibilityEvent(event); 41949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // This view masquerades as an action bar tab. 42049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes event.setClassName(ActionBar.Tab.class.getName()); 42149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 42249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 42349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 42449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 42549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onInitializeAccessibilityNodeInfo(info); 42649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 42749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (Build.VERSION.SDK_INT >= 14) { 42849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // This view masquerades as an action bar tab. 42949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes info.setClassName(ActionBar.Tab.class.getName()); 43049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 43149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 43249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 43349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 434ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 435ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 436bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 437ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Re-measure if we went beyond our maximum size. 43849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) { 43949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY), 44020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns heightMeasureSpec); 441ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 442ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 443bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 444ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void update() { 445ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ActionBar.Tab tab = mTab; 446ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View custom = tab.getCustomView(); 447ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (custom != null) { 448ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ViewParent customParent = custom.getParent(); 449ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (customParent != this) { 45049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (customParent != null) ((ViewGroup) customParent).removeView(custom); 451ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(custom); 452ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 453ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mCustomView = custom; 45449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mTextView != null) mTextView.setVisibility(GONE); 455ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView != null) { 456ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(GONE); 457ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(null); 458ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 459ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 460ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mCustomView != null) { 461ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mCustomView); 462ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mCustomView = null; 463ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 464ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 465ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Drawable icon = tab.getIcon(); 466ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final CharSequence text = tab.getText(); 467ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 468ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (icon != null) { 469ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView == null) { 470ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ImageView iconView = new ImageView(getContext()); 471ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 47220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 473ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani lp.gravity = Gravity.CENTER_VERTICAL; 474ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani iconView.setLayoutParams(lp); 475ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(iconView, 0); 476ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView = iconView; 477ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 478ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(icon); 479ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(VISIBLE); 480ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (mIconView != null) { 481ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(GONE); 482ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(null); 483ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 484ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 48549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean hasText = !TextUtils.isEmpty(text); 48649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (hasText) { 487ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTextView == null) { 4882cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes TextView textView = new AppCompatTextView(getContext(), null, 48920ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.attr.actionBarTabTextStyle); 490ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani textView.setEllipsize(TruncateAt.END); 491ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 49220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 493ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani lp.gravity = Gravity.CENTER_VERTICAL; 494ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani textView.setLayoutParams(lp); 495ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(textView); 496ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView = textView; 497ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 498ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setText(text); 499ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setVisibility(VISIBLE); 500ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (mTextView != null) { 501ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setVisibility(GONE); 502ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setText(null); 503ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 504ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 505ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView != null) { 506ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setContentDescription(tab.getContentDescription()); 507ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 50849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 50949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) { 51049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setOnLongClickListener(this); 51149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 51249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setOnLongClickListener(null); 51349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setLongClickable(false); 51449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 515ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 516ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 517bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 51849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onLongClick(View v) { 51949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int[] screenPos = new int[2]; 52049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes getLocationOnScreen(screenPos); 52149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 52249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Context context = getContext(); 52349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int width = getWidth(); 52449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int height = getHeight(); 52549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; 52649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 52749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(), 52849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Toast.LENGTH_SHORT); 52949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Show under the tab 53049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 53149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes (screenPos[0] + width / 2) - screenWidth / 2, height); 53249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 53349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes cheatSheet.show(); 53449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return true; 53549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 53649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 537ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionBar.Tab getTab() { 538ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTab; 539ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 540bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 541bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 542ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class TabAdapter extends BaseAdapter { 543ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 544ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public int getCount() { 545ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTabLayout.getChildCount(); 546ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 547bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 548ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 549ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public Object getItem(int position) { 550ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return ((TabView) mTabLayout.getChildAt(position)).getTab(); 551ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 552bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 553ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 554ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public long getItemId(int position) { 555ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return position; 556ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 557bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 558ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 559ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public View getView(int position, View convertView, ViewGroup parent) { 560ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (convertView == null) { 561ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani convertView = createTabView((ActionBar.Tab) getItem(position), true); 562ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 563ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position)); 564ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 565ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return convertView; 566ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 567bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 568bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 569ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class TabClickListener implements OnClickListener { 570ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onClick(View view) { 571ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = (TabView) view; 572ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.getTab().select(); 573ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int tabCount = mTabLayout.getChildCount(); 574ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < tabCount; i++) { 575ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View child = mTabLayout.getChildAt(i); 576ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani child.setSelected(child == view); 577ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 578ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 579bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 580bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 58149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected class VisibilityAnimListener implements ViewPropertyAnimatorListener { 58249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private boolean mCanceled = false; 58349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mFinalVisibility; 58449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 58549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public VisibilityAnimListener withFinalVisibility(ViewPropertyAnimatorCompat animation, 58649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int visibility) { 58749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mFinalVisibility = visibility; 58849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim = animation; 58949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return this; 59049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 59149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 59249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 59349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationStart(View view) { 59449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setVisibility(VISIBLE); 59549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mCanceled = false; 59649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 59749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 59849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 59949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationEnd(View view) { 60049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mCanceled) return; 60149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 60249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim = null; 60349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setVisibility(mFinalVisibility); 60449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 60549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 60649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 60749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationCancel(View view) { 60849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mCanceled = true; 60949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 61049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 611bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 612ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 613