ScrollingTabContainerView.java revision 66698bb15ba0f873aa1c2290cc50d6bb839a474a
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) { 22049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (Build.VERSION.SDK_INT >= 8) { 22149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onConfigurationChanged(newConfig); 22249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 22349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ActionBarPolicy abp = ActionBarPolicy.get(getContext()); 225ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Action bar can change size on configuration changes. 226ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Reread the desired height from the theme-specified style. 227ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setContentHeight(abp.getTabContainerHeight()); 228ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); 229bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 230ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 23149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void animateToVisibility(int visibility) { 23249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mVisibilityAnim != null) { 23349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim.cancel(); 23449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 23549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (visibility == VISIBLE) { 23649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (getVisibility() != VISIBLE) { 23749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewCompat.setAlpha(this, 0f); 23849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 23949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f); 24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setDuration(FADE_DURATION); 24249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setInterpolator(sAlphaInterpolator); 24449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); 24549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.start(); 24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 24749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f); 24849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setDuration(FADE_DURATION); 24949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 25049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setInterpolator(sAlphaInterpolator); 25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); 25249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.start(); 25349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 25449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 25549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 256ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void animateToTab(final int position) { 257ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View tabView = mTabLayout.getChildAt(position); 258ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 261ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = new Runnable() { 262ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void run() { 263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2; 264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani smoothScrollTo(scrollPos, 0); 265ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = null; 266ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 267ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani }; 268ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani post(mTabSelector); 269bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onAttachedToWindow() { 273ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onAttachedToWindow(); 274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Re-post the selector we saved 276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani post(mTabSelector); 277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 278bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onDetachedFromWindow() { 282ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onDetachedFromWindow(); 283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 286bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) { 28949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final TabView tabView = new TabView(getContext(), tab, forAdapter); 290ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (forAdapter) { 291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setBackgroundDrawable(null); 29249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, 29320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mContentHeight)); 294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setFocusable(true); 296ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabClickListener == null) { 298ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabClickListener = new TabClickListener(); 299ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 300ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setOnClickListener(mTabClickListener); 301ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return tabView; 303bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 304bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 305ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void addTab(ActionBar.Tab tab, boolean setSelected) { 306ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = createTabView(tab, false); 30749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout.addView(tabView, new LinearLayoutCompat.LayoutParams(0, 30849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes LayoutParams.MATCH_PARENT, 1)); 309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 310ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 311ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 312ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (setSelected) { 313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setSelected(true); 314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 316ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 318bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 320ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { 321ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final TabView tabView = createTabView(tab, false); 32249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout.addView(tabView, position, new LinearLayoutCompat.LayoutParams( 32349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 0, LayoutParams.MATCH_PARENT, 1)); 324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 326ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 327ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (setSelected) { 328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setSelected(true); 329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 331ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 332ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 333bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 334bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void updateTab(int position) { 336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabView) mTabLayout.getChildAt(position)).update(); 337ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 338ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 339ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 341ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 343bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void removeTabAt(int position) { 346ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.removeViewAt(position); 347ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 348ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 350ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 351ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 352ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 353bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 354bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 355ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void removeAllTabs() { 356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.removeAllViews(); 357ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 358ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 359ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 361ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 363bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 364ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 366f933672168f6deff5e3636584bec735416b5a93bChris Banes public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { 367ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = (TabView) view; 368ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.getTab().select(); 369bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 370bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 371f933672168f6deff5e3636584bec735416b5a93bChris Banes @Override 372f933672168f6deff5e3636584bec735416b5a93bChris Banes public void onNothingSelected(AdapterView<?> adapterView) { 373f933672168f6deff5e3636584bec735416b5a93bChris Banes // no-op 374f933672168f6deff5e3636584bec735416b5a93bChris Banes } 375f933672168f6deff5e3636584bec735416b5a93bChris Banes 37649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private class TabView extends LinearLayoutCompat implements OnLongClickListener { 377469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private final int[] BG_ATTRS = { 378469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes android.R.attr.background 379469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 380469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 381ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ActionBar.Tab mTab; 382ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TextView mTextView; 383ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ImageView mIconView; 384ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private View mCustomView; 385bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 38649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public TabView(Context context, ActionBar.Tab tab, boolean forList) { 38749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(context, null, R.attr.actionBarTabStyle); 388ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTab = tab; 38934b5c9580dd01b4428ab2c5990add571eaab6b13Trevor Johns 390469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, null, BG_ATTRS, 391469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.attr.actionBarTabStyle, 0); 392469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (a.hasValue(0)) { 393469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes setBackgroundDrawable(a.getDrawable(0)); 394469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 395469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes a.recycle(); 396469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 397ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (forList) { 39849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setGravity(GravityCompat.START | Gravity.CENTER_VERTICAL); 399ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 400bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 401ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani update(); 402ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 403bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 404ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void bindTab(ActionBar.Tab tab) { 405ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTab = tab; 406ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani update(); 407ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 408bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 409ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 41049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setSelected(boolean selected) { 41149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean changed = (isSelected() != selected); 41249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.setSelected(selected); 41349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (changed && selected) { 41449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 41549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 41649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 41749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 41849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 41949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 42049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onInitializeAccessibilityEvent(event); 42149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // This view masquerades as an action bar tab. 42249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes event.setClassName(ActionBar.Tab.class.getName()); 42349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 42449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 42549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 42649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 42749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onInitializeAccessibilityNodeInfo(info); 42849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 42949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (Build.VERSION.SDK_INT >= 14) { 43049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // This view masquerades as an action bar tab. 43149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes info.setClassName(ActionBar.Tab.class.getName()); 43249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 43349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 43449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 43549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 436ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 437ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 438bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 439ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Re-measure if we went beyond our maximum size. 44049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) { 44149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY), 44220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns heightMeasureSpec); 443ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 444ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 445bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 446ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void update() { 447ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ActionBar.Tab tab = mTab; 448ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View custom = tab.getCustomView(); 449ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (custom != null) { 450ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ViewParent customParent = custom.getParent(); 451ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (customParent != this) { 45249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (customParent != null) ((ViewGroup) customParent).removeView(custom); 453ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(custom); 454ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 455ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mCustomView = custom; 45649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mTextView != null) mTextView.setVisibility(GONE); 457ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView != null) { 458ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(GONE); 459ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(null); 460ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 461ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 462ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mCustomView != null) { 463ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mCustomView); 464ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mCustomView = null; 465ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 466ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 467ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Drawable icon = tab.getIcon(); 468ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final CharSequence text = tab.getText(); 469ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 470ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (icon != null) { 471ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView == null) { 472ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ImageView iconView = new ImageView(getContext()); 473ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 47420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 475ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani lp.gravity = Gravity.CENTER_VERTICAL; 476ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani iconView.setLayoutParams(lp); 477ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(iconView, 0); 478ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView = iconView; 479ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 480ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(icon); 481ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(VISIBLE); 482ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (mIconView != null) { 483ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(GONE); 484ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(null); 485ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 486ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 48749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean hasText = !TextUtils.isEmpty(text); 48849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (hasText) { 489ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTextView == null) { 4902cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes TextView textView = new AppCompatTextView(getContext(), null, 49120ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.attr.actionBarTabTextStyle); 492ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani textView.setEllipsize(TruncateAt.END); 493ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 49420ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 495ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani lp.gravity = Gravity.CENTER_VERTICAL; 496ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani textView.setLayoutParams(lp); 497ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(textView); 498ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView = textView; 499ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 500ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setText(text); 501ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setVisibility(VISIBLE); 502ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (mTextView != null) { 503ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setVisibility(GONE); 504ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setText(null); 505ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 506ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 507ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView != null) { 508ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setContentDescription(tab.getContentDescription()); 509ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 51049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 51149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) { 51249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setOnLongClickListener(this); 51349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 51449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setOnLongClickListener(null); 51549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setLongClickable(false); 51649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 517ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 518ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 519bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 52049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onLongClick(View v) { 52149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int[] screenPos = new int[2]; 52249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes getLocationOnScreen(screenPos); 52349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 52449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Context context = getContext(); 52549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int width = getWidth(); 52649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int height = getHeight(); 52749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; 52849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 52949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(), 53049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Toast.LENGTH_SHORT); 53149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Show under the tab 53249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 53349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes (screenPos[0] + width / 2) - screenWidth / 2, height); 53449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 53549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes cheatSheet.show(); 53649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return true; 53749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 53849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 539ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionBar.Tab getTab() { 540ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTab; 541ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 542bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 543bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 544ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class TabAdapter extends BaseAdapter { 545ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 546ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public int getCount() { 547ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTabLayout.getChildCount(); 548ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 549bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 550ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 551ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public Object getItem(int position) { 552ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return ((TabView) mTabLayout.getChildAt(position)).getTab(); 553ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 554bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 555ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 556ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public long getItemId(int position) { 557ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return position; 558ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 559bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 560ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 561ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public View getView(int position, View convertView, ViewGroup parent) { 562ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (convertView == null) { 563ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani convertView = createTabView((ActionBar.Tab) getItem(position), true); 564ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 565ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position)); 566ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 567ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return convertView; 568ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 569bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 570bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 571ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class TabClickListener implements OnClickListener { 572ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onClick(View view) { 573ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = (TabView) view; 574ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.getTab().select(); 575ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int tabCount = mTabLayout.getChildCount(); 576ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < tabCount; i++) { 577ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View child = mTabLayout.getChildAt(i); 578ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani child.setSelected(child == view); 579ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 580ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 581bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 582bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 58349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected class VisibilityAnimListener implements ViewPropertyAnimatorListener { 58449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private boolean mCanceled = false; 58549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mFinalVisibility; 58649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 58749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public VisibilityAnimListener withFinalVisibility(ViewPropertyAnimatorCompat animation, 58849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int visibility) { 58949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mFinalVisibility = visibility; 59049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim = animation; 59149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return this; 59249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 59349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 59449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 59549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationStart(View view) { 59649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setVisibility(VISIBLE); 59749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mCanceled = false; 59849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 59949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 60049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 60149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationEnd(View view) { 60249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mCanceled) return; 60349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 60449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim = null; 60549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setVisibility(mFinalVisibility); 60649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 60749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 60849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 60949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationCancel(View view) { 61049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mCanceled = true; 61149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 61249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 613bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 614ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 615