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; 22c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 2349c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.GravityCompat; 2449c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewCompat; 2549c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorCompat; 2649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.support.v4.view.ViewPropertyAnimatorListener; 27da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.app.ActionBar; 28da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R; 2966698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banesimport android.support.v7.view.ActionBarPolicy; 3049c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.text.TextUtils; 31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.text.TextUtils.TruncateAt; 32bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.Gravity; 33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View; 34bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewGroup; 35bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.ViewParent; 3649c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.accessibility.AccessibilityEvent; 3749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.accessibility.AccessibilityNodeInfo; 3849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.animation.DecelerateInterpolator; 3949c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.animation.Interpolator; 40f933672168f6deff5e3636584bec735416b5a93bChris Banesimport android.widget.AdapterView; 41bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.BaseAdapter; 42bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.HorizontalScrollView; 43bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ImageView; 44bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.ListView; 45f933672168f6deff5e3636584bec735416b5a93bChris Banesimport android.widget.Spinner; 46bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.widget.TextView; 4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.widget.Toast; 48bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 49c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport static android.support.annotation.RestrictTo.Scope.GROUP_ID; 50c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette 51bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 5220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * This widget implements the dynamic action bar tab behavior that can change across different 5320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns * configurations or circumstances. 5489208232f3b5d1451408d787872504a190bc7ee0Chris Banes * 5589208232f3b5d1451408d787872504a190bc7ee0Chris Banes * @hide 56bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 57c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette@RestrictTo(GROUP_ID) 58bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellpublic class ScrollingTabContainerView extends HorizontalScrollView 59f933672168f6deff5e3636584bec735416b5a93bChris Banes implements AdapterView.OnItemSelectedListener { 6020ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns 61ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private static final String TAG = "ScrollingTabContainerView"; 62ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani Runnable mTabSelector; 63ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TabClickListener mTabClickListener; 64bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 652c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas LinearLayoutCompat mTabLayout; 66f933672168f6deff5e3636584bec735416b5a93bChris Banes private Spinner mTabSpinner; 67ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean mAllowCollapse; 68bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 69ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani int mMaxTabWidth; 70ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani int mStackedTabMaxWidth; 71ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mContentHeight; 72ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private int mSelectedTabIndex; 73bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 7449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected ViewPropertyAnimatorCompat mVisibilityAnim; 7549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); 7649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final Interpolator sAlphaInterpolator = new DecelerateInterpolator(); 7849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 7949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private static final int FADE_DURATION = 200; 8049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 81ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ScrollingTabContainerView(Context context) { 82ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super(context); 83624d7ed5e2d6dc7a937468dda7bef1f65cd765d7Chris Banes 84ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setHorizontalScrollBarEnabled(false); 85bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 86ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ActionBarPolicy abp = ActionBarPolicy.get(context); 87ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setContentHeight(abp.getTabContainerHeight()); 88ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); 89bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 9049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout = createTabLayout(); 91ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 9249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.MATCH_PARENT)); 93bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 94ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 95ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 96ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 97ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 98ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY; 99ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setFillViewport(lockedExpanded); 100ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 101ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int childCount = mTabLayout.getChildCount(); 102ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (childCount > 1 && 10320ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) { 104ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (childCount > 2) { 105ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f); 106ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 107ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2; 108ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 109ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = Math.min(mMaxTabWidth, mStackedTabMaxWidth); 110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 111ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMaxTabWidth = -1; 112ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 113ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 114ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY); 115ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 116ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean canCollapse = !lockedExpanded && mAllowCollapse; 117ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 118ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (canCollapse) { 119ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // See if we should expand 120ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec); 121ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) { 122ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani performCollapse(); 123ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 124ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani performExpand(); 125ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 126ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 127ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani performExpand(); 128ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int oldWidth = getMeasuredWidth(); 131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 132ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int newWidth = getMeasuredWidth(); 133ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 134ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (lockedExpanded && oldWidth != newWidth) { 135ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Recenter the tab display if we're at a new (scrollable) size. 136ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setTabSelected(mSelectedTabIndex); 137ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 138bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 139ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 140ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani /** 14149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * Indicates whether this view is collapsed into a dropdown menu instead 14249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes * of traditional tabs. 143ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani * @return true if showing as a spinner 144ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani */ 145ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean isCollapsed() { 146ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTabSpinner != null && mTabSpinner.getParent() == this; 147bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 148ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 149ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setAllowCollapse(boolean allowCollapse) { 150ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mAllowCollapse = allowCollapse; 151bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 152ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 153ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private void performCollapse() { 15449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (isCollapsed()) return; 155ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 156ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner == null) { 157ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSpinner = createSpinner(); 158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 159ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mTabLayout); 160ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 16149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.MATCH_PARENT)); 162ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner.getAdapter() == null) { 163ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSpinner.setAdapter(new TabAdapter()); 164ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 166ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = null; 168ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 169ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSpinner.setSelection(mSelectedTabIndex); 170bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 171ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 172ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private boolean performExpand() { 17349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!isCollapsed()) return false; 174ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 175ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mTabSpinner); 176ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 17749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewGroup.LayoutParams.MATCH_PARENT)); 178ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setTabSelected(mTabSpinner.getSelectedItemPosition()); 179ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return false; 180bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 181ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 182ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setTabSelected(int position) { 183ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mSelectedTabIndex = position; 184ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int tabCount = mTabLayout.getChildCount(); 185ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < tabCount; i++) { 186ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View child = mTabLayout.getChildAt(i); 187ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final boolean isSelected = i == position; 188ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani child.setSelected(isSelected); 189ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (isSelected) { 190ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani animateToTab(position); 191ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 193b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes if (mTabSpinner != null && position >= 0) { 194b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes mTabSpinner.setSelection(position); 195b0e48446da2cb1e18a0166fbfab9c6aa19430d76Chris Banes } 196bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 197bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 198ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void setContentHeight(int contentHeight) { 199ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mContentHeight = contentHeight; 200ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 201bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 202ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 20349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private LinearLayoutCompat createTabLayout() { 20449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final LinearLayoutCompat tabLayout = new LinearLayoutCompat(getContext(), null, 20549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes R.attr.actionBarTabBarStyle); 20649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabLayout.setMeasureWithLargestChildEnabled(true); 20749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabLayout.setGravity(Gravity.CENTER); 20849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabLayout.setLayoutParams(new LinearLayoutCompat.LayoutParams( 20949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes LinearLayoutCompat.LayoutParams.WRAP_CONTENT, LinearLayoutCompat.LayoutParams.MATCH_PARENT)); 21049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return tabLayout; 21149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 21249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 213f933672168f6deff5e3636584bec735416b5a93bChris Banes private Spinner createSpinner() { 214f933672168f6deff5e3636584bec735416b5a93bChris Banes final Spinner spinner = new AppCompatSpinner(getContext(), null, 21520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.attr.actionDropDownStyle); 21649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes spinner.setLayoutParams(new LinearLayoutCompat.LayoutParams( 217f933672168f6deff5e3636584bec735416b5a93bChris Banes LinearLayoutCompat.LayoutParams.WRAP_CONTENT, 218f933672168f6deff5e3636584bec735416b5a93bChris Banes LinearLayoutCompat.LayoutParams.MATCH_PARENT)); 219f933672168f6deff5e3636584bec735416b5a93bChris Banes spinner.setOnItemSelectedListener(this); 220ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return spinner; 221bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 222ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 223dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 224ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani protected void onConfigurationChanged(Configuration newConfig) { 22564dbe1d454f1190b3cd8426d09b9119949a10709Kirill Grouchnikov super.onConfigurationChanged(newConfig); 22649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 227ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ActionBarPolicy abp = ActionBarPolicy.get(getContext()); 228ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Action bar can change size on configuration changes. 229ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Reread the desired height from the theme-specified style. 230ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani setContentHeight(abp.getTabContainerHeight()); 231ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mStackedTabMaxWidth = abp.getStackedTabMaxWidth(); 232bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 233ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 23449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void animateToVisibility(int visibility) { 23549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mVisibilityAnim != null) { 23649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim.cancel(); 23749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 23849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (visibility == VISIBLE) { 23949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (getVisibility() != VISIBLE) { 24049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewCompat.setAlpha(this, 0f); 24149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 24249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(1f); 24449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setDuration(FADE_DURATION); 24549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 24649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setInterpolator(sAlphaInterpolator); 24749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); 24849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.start(); 24949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 25049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes ViewPropertyAnimatorCompat anim = ViewCompat.animate(this).alpha(0f); 25149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setDuration(FADE_DURATION); 25249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 25349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setInterpolator(sAlphaInterpolator); 25449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.setListener(mVisAnimListener.withFinalVisibility(anim, visibility)); 25549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes anim.start(); 25649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 25749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 25849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 259ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void animateToTab(final int position) { 260ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View tabView = mTabLayout.getChildAt(position); 261ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 262ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 263ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 264ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = new Runnable() { 265dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 266ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void run() { 267ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2; 268ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani smoothScrollTo(scrollPos, 0); 269ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabSelector = null; 270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 271ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani }; 272ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani post(mTabSelector); 273bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 275ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 276ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onAttachedToWindow() { 277ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onAttachedToWindow(); 278ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 279ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Re-post the selector we saved 280ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani post(mTabSelector); 281ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 282bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 283ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 284ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 285ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onDetachedFromWindow() { 286ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onDetachedFromWindow(); 287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSelector != null) { 288ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeCallbacks(mTabSelector); 289ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 290bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 291ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 2922c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas TabView createTabView(ActionBar.Tab tab, boolean forAdapter) { 29349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final TabView tabView = new TabView(getContext(), tab, forAdapter); 294ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (forAdapter) { 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setBackgroundDrawable(null); 29649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, 29720ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns mContentHeight)); 298ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 299ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setFocusable(true); 300ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 301ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabClickListener == null) { 302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabClickListener = new TabClickListener(); 303ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setOnClickListener(mTabClickListener); 305ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 306ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return tabView; 307bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 308bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void addTab(ActionBar.Tab tab, boolean setSelected) { 310ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = createTabView(tab, false); 31149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout.addView(tabView, new LinearLayoutCompat.LayoutParams(0, 31249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes LayoutParams.MATCH_PARENT, 1)); 313ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 314ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 315ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 316ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (setSelected) { 317ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setSelected(true); 318ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 319ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 320ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 321ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 322bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 323ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 324ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { 325ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final TabView tabView = createTabView(tab, false); 32649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mTabLayout.addView(tabView, position, new LinearLayoutCompat.LayoutParams( 32749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 0, LayoutParams.MATCH_PARENT, 1)); 328ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 329ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 330ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 331ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (setSelected) { 332ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.setSelected(true); 333ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 334ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 335ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 336ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 337bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 338bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 339ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void updateTab(int position) { 340ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabView) mTabLayout.getChildAt(position)).update(); 341ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 342ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 343ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 344ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 345ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 346ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 347bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 348ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 349ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void removeTabAt(int position) { 350ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.removeViewAt(position); 351ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 352ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 353ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 354ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 355ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 356ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 357bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 358bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 359ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void removeAllTabs() { 360ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTabLayout.removeAllViews(); 361ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTabSpinner != null) { 362ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); 363ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 364ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mAllowCollapse) { 365ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani requestLayout(); 366ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 367bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 368ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 369ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 370f933672168f6deff5e3636584bec735416b5a93bChris Banes public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { 371ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = (TabView) view; 372ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.getTab().select(); 373bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 374bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 375f933672168f6deff5e3636584bec735416b5a93bChris Banes @Override 376f933672168f6deff5e3636584bec735416b5a93bChris Banes public void onNothingSelected(AdapterView<?> adapterView) { 377f933672168f6deff5e3636584bec735416b5a93bChris Banes // no-op 378f933672168f6deff5e3636584bec735416b5a93bChris Banes } 379f933672168f6deff5e3636584bec735416b5a93bChris Banes 38049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private class TabView extends LinearLayoutCompat implements OnLongClickListener { 381469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private final int[] BG_ATTRS = { 382469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes android.R.attr.background 383469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 384469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 385ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ActionBar.Tab mTab; 386ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private TextView mTextView; 387ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private ImageView mIconView; 388ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private View mCustomView; 389bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 39049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public TabView(Context context, ActionBar.Tab tab, boolean forList) { 39149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super(context, null, R.attr.actionBarTabStyle); 392ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTab = tab; 39334b5c9580dd01b4428ab2c5990add571eaab6b13Trevor Johns 394469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, null, BG_ATTRS, 395469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.attr.actionBarTabStyle, 0); 396469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (a.hasValue(0)) { 397469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes setBackgroundDrawable(a.getDrawable(0)); 398469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 399469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes a.recycle(); 400469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 401ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (forList) { 40249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setGravity(GravityCompat.START | Gravity.CENTER_VERTICAL); 403ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 404bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 405ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani update(); 406ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 407bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 408ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void bindTab(ActionBar.Tab tab) { 409ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTab = tab; 410ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani update(); 411ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 412bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 413ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 41449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setSelected(boolean selected) { 41549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean changed = (isSelected() != selected); 41649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.setSelected(selected); 41749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (changed && selected) { 41849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 41949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 42049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 42149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 42249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 42349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 42449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onInitializeAccessibilityEvent(event); 42549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // This view masquerades as an action bar tab. 42649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes event.setClassName(ActionBar.Tab.class.getName()); 42749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 42849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 42949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 43049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 43149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onInitializeAccessibilityNodeInfo(info); 43249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 43349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (Build.VERSION.SDK_INT >= 14) { 43449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // This view masquerades as an action bar tab. 43549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes info.setClassName(ActionBar.Tab.class.getName()); 43649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 43749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 43849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 43949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 440ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 441ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani super.onMeasure(widthMeasureSpec, heightMeasureSpec); 442bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 443ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani // Re-measure if we went beyond our maximum size. 44449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) { 44549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY), 44620ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns heightMeasureSpec); 447ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 448ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 449bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 450ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void update() { 451ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ActionBar.Tab tab = mTab; 452ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View custom = tab.getCustomView(); 453ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (custom != null) { 454ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final ViewParent customParent = custom.getParent(); 455ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (customParent != this) { 45649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (customParent != null) ((ViewGroup) customParent).removeView(custom); 457ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(custom); 458ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 459ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mCustomView = custom; 46049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mTextView != null) mTextView.setVisibility(GONE); 461ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView != null) { 462ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(GONE); 463ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(null); 464ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 465ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 466ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mCustomView != null) { 467ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani removeView(mCustomView); 468ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mCustomView = null; 469ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 470ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 471ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final Drawable icon = tab.getIcon(); 472ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final CharSequence text = tab.getText(); 473ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 474ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (icon != null) { 475ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView == null) { 47619ef8b22fccfd1649ac27cec9fe74933265f5745Chris Banes ImageView iconView = new AppCompatImageView(getContext()); 477ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 47820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 479ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani lp.gravity = Gravity.CENTER_VERTICAL; 480ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani iconView.setLayoutParams(lp); 481ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(iconView, 0); 482ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView = iconView; 483ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 484ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(icon); 485ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(VISIBLE); 486ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (mIconView != null) { 487ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setVisibility(GONE); 488ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setImageDrawable(null); 489ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 490ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 49149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final boolean hasText = !TextUtils.isEmpty(text); 49249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (hasText) { 493ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mTextView == null) { 4942cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes TextView textView = new AppCompatTextView(getContext(), null, 49520ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns R.attr.actionBarTabTextStyle); 496ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani textView.setEllipsize(TruncateAt.END); 497ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, 49820ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns LayoutParams.WRAP_CONTENT); 499ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani lp.gravity = Gravity.CENTER_VERTICAL; 500ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani textView.setLayoutParams(lp); 501ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani addView(textView); 502ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView = textView; 503ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 504ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setText(text); 505ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setVisibility(VISIBLE); 506ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else if (mTextView != null) { 507ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setVisibility(GONE); 508ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mTextView.setText(null); 509ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 510ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 511ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (mIconView != null) { 512ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mIconView.setContentDescription(tab.getContentDescription()); 513ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 51449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 51549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (!hasText && !TextUtils.isEmpty(tab.getContentDescription())) { 51649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setOnLongClickListener(this); 51749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } else { 51849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setOnLongClickListener(null); 51949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setLongClickable(false); 52049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 521ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 522ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 523bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 524dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 52549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public boolean onLongClick(View v) { 52649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int[] screenPos = new int[2]; 52749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes getLocationOnScreen(screenPos); 52849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 52949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final Context context = getContext(); 53049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int width = getWidth(); 53149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int height = getHeight(); 53249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; 53349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 53449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Toast cheatSheet = Toast.makeText(context, mTab.getContentDescription(), 53549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes Toast.LENGTH_SHORT); 53649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes // Show under the tab 53749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 53849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes (screenPos[0] + width / 2) - screenWidth / 2, height); 53949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 54049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes cheatSheet.show(); 54149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return true; 54249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 54349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 544ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public ActionBar.Tab getTab() { 545ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTab; 546ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 547bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 548bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 549ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class TabAdapter extends BaseAdapter { 5502c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas TabAdapter() { 5512c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas } 5522c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas 553ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 554ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public int getCount() { 555ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return mTabLayout.getChildCount(); 556ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 557bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 558ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 559ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public Object getItem(int position) { 560ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return ((TabView) mTabLayout.getChildAt(position)).getTab(); 561ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 562bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 563ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 564ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public long getItemId(int position) { 565ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return position; 566ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 567bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 568ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 569ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public View getView(int position, View convertView, ViewGroup parent) { 570ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (convertView == null) { 571ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani convertView = createTabView((ActionBar.Tab) getItem(position), true); 572ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } else { 573ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position)); 574ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 575ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return convertView; 576ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 577bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 578bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 579ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private class TabClickListener implements OnClickListener { 5802c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas TabClickListener() { 5812c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas } 5822c1bad7ecd5879bf0f29ce2ce1bc5bd67a3f4682Aurimas Liutikas 583dc8e099ed130434c0238f558277c5bcb6a533121Aurimas Liutikas @Override 584ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void onClick(View view) { 585ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani TabView tabView = (TabView) view; 586ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani tabView.getTab().select(); 587ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final int tabCount = mTabLayout.getChildCount(); 588ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani for (int i = 0; i < tabCount; i++) { 589ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani final View child = mTabLayout.getChildAt(i); 590ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani child.setSelected(child == view); 591ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 592ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 593bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 594bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 59549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes protected class VisibilityAnimListener implements ViewPropertyAnimatorListener { 59649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private boolean mCanceled = false; 59749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private int mFinalVisibility; 59849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 59949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public VisibilityAnimListener withFinalVisibility(ViewPropertyAnimatorCompat animation, 60049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes int visibility) { 60149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mFinalVisibility = visibility; 60249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim = animation; 60349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return this; 60449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 60549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 60649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 60749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationStart(View view) { 60849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setVisibility(VISIBLE); 60949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mCanceled = false; 61049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 61149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 61249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 61349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationEnd(View view) { 61449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes if (mCanceled) return; 61549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 61649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mVisibilityAnim = null; 61749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes setVisibility(mFinalVisibility); 61849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 61949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 62049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes @Override 62149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void onAnimationCancel(View view) { 62249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mCanceled = true; 62349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 62449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 625bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 626ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 627