/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.tencent.tws.assistant.internal.widget; import java.util.ArrayList; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.app.TwsActivity; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.util.AttributeSet; import android.util.IntProperty; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.TextView; import com.tencent.tws.assistant.app.ActionBar; import com.tencent.tws.assistant.utils.ResIdentifierUtils; import com.tencent.tws.assistant.utils.ThemeUtils; import com.tencent.tws.sharelib.R; /** * This widget implements the dynamic action bar tab behavior that can change * across different configurations or circumstances. */ public class ScrollingTabContainerView extends HorizontalScrollView implements AdapterView.OnItemSelectedListener { private static final String TAG = "ScrollingTabContainerView"; Runnable mTabSelector; private TabClickListener mTabClickListener; private int mTabMode = ActionBar.ACTIONBAR_TAB_STANDARD; private LinearLayout mTabLayout; private RelativeLayout mTabOutLayout; private Spinner mTabSpinner; private boolean mAllowCollapse; int mMaxTabWidth; private int mContentHeight; private int mSelectedTabIndex; protected Animator mVisibilityAnim; protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator(); private static final int FADE_DURATION = 200; private ActionBarContextView mContextView; // tws-start add smooth scroll feature to tab::2014-11-18 private boolean mInit = false; private int mSelectedColor = 0; private int mNormalColor = 0; private ColorStateList mNormalColors; private Rect mIndicatorRect = new Rect(); private Drawable mIndicator = null; private boolean mDrawIndicator = false; ArrayList<Drawable> mDrawableDepot = new ArrayList<Drawable>(); // tws-end add smooth scroll feature to tab ::2014-11-18 private HorizontalWaveView mWaveView; private int mWScrollCnt; private int mAmplitude; private int mBeforeTabPostion; private int mWaveHeight; private Drawable mStackDrawable; private boolean mTabWaveEnable; private float mAnimStart, mAnimEnd; private boolean mHasPageScrolled, mHasPageSelected, mPageSelectedNeedReset; private float mIndicatorViewOffset; private boolean mTabTextSelectChange; private View mLeftView, mRightView; private boolean mTabButtonEnable; private boolean mFirstBuildTab = true; private int mActionBarTabTheme; private boolean mActionBarTabThemeWave; private Animator mAMAnimator; public ScrollingTabContainerView(Context context) { this(context, ActionBar.ACTIONBAR_TAB_STANDARD, false, false); } public ScrollingTabContainerView(Context context, int tabMode, boolean hasButton, boolean tabWaveEnable) { super(context); mTabMode = tabMode; mTabButtonEnable = hasButton; mTabWaveEnable = tabWaveEnable; setHorizontalScrollBarEnabled(false); TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, R.attr.actionBarStyle, 0); setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); mActionBarTabThemeWave = ThemeUtils.isActionBarTabStyleWave(context); mActionBarTabTheme = a.getInt(R.styleable.ActionBar_actionbartabTheme, ThemeUtils.ACTIONBARTAB_THEME_NORMAL); if (!(mActionBarTabThemeWave && mActionBarTabTheme == ThemeUtils.ACTIONBARTAB_THEME_WAVE)) { mTabWaveEnable = false; } setTabContentHeight(mTabMode); a.recycle(); FrameLayout frameLayout = new FrameLayout(context); frameLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); if (mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY || mTabMode == ActionBar.ACTIONBAR_TAB_STANDARD) { mWaveHeight = mContentHeight-getPaddingTop(); } else if (mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY_SECOND || mTabMode == ActionBar.ACTIONBAR_TAB_STANDARD_SECOND) { mWaveHeight = mContentHeight+(int)getResources().getDimension(R.dimen.tws_action_bar_shadow_height); } mWaveView = new HorizontalWaveView(context, mWaveHeight); if (!mTabWaveEnable) mWaveView.setVisibility(View.GONE); mIndicatorViewOffset = getResources().getDimension(R.dimen.tws_actionbartab_overlay_offset); mAnimStart = mWaveHeight + (int)getResources().getDimension(R.dimen.tws_actionbartab_second_overlay_padding); mAnimEnd = mAnimStart - mIndicatorViewOffset; frameLayout.addView(mWaveView); mAMAnimator = ObjectAnimator.ofInt(mWaveView, AM_VALUE, 5, 0); mAMAnimator.setDuration(500); if (hasButton) { mTabLayout = createTabInternalLayout(); mTabOutLayout = createTabRelativeLayout(); } else { mTabLayout = createTabLayout(); } if (mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY) { mAnimStart = mWaveHeight - (tabWaveEnable ? (int)getResources().getDimension(R.dimen.tws_actionbartab_overlay_padding_tab) : (int)getResources().getDimension(R.dimen.tws_actionbartab_overlay_padding)); mAnimEnd = mAnimStart - mIndicatorViewOffset; mTabLayout.setPadding(0, TwsActivity.getStatusBarHeight(), 0, 0); } if (hasButton) { frameLayout.addView(mTabOutLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } else { frameLayout.addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } addView(frameLayout); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY; setFillViewport(lockedExpanded); final int childCount = mTabLayout.getChildCount(); if (childCount > 1 && (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) { if (childCount > 2) { mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f); } else { mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2; } } else { mMaxTabWidth = -1; } heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY); final boolean canCollapse = !lockedExpanded && mAllowCollapse; if (canCollapse) { // See if we should expand mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec); if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) { performCollapse(); } else { performExpand(); } } else { performExpand(); } final int oldWidth = getMeasuredWidth(); super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int newWidth = getMeasuredWidth(); if (lockedExpanded && oldWidth != newWidth) { // Recenter the tab display if we're at a new (scrollable) size. setTabSelected(mSelectedTabIndex); } if (mContextView != null && mTabMode != ActionBar.ACTIONBAR_TAB_STANDARD) { mContextView.setContentHeight(mContentHeight); mContextView.setPadding(0, getPaddingTop()+TwsActivity.getStatusBarHeight(), 0, 0); } } public void setContextView(ActionBarContextView view) { mContextView = view; } /** * Indicates whether this view is collapsed into a dropdown menu instead * of traditional tabs. * @return true if showing as a spinner */ private boolean isCollapsed() { return mTabSpinner != null && mTabSpinner.getParent() == this; } public void setAllowCollapse(boolean allowCollapse) { mAllowCollapse = allowCollapse; } private void performCollapse() { if (isCollapsed()) return; if (mTabSpinner == null) { mTabSpinner = createSpinner(); } removeView(mTabLayout); addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); if (mTabSpinner.getAdapter() == null) { mTabSpinner.setAdapter(new TabAdapter()); } if (mTabSelector != null) { removeCallbacks(mTabSelector); mTabSelector = null; } mTabSpinner.setSelection(mSelectedTabIndex); } private boolean performExpand() { if (!isCollapsed()) return false; removeView(mTabSpinner); addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); setTabSelected(mTabSpinner.getSelectedItemPosition()); return false; } public void setTabSelected(int position) { mSelectedTabIndex = position; final int tabCount = mTabLayout.getChildCount(); for (int i = 0; i < tabCount; i++) { final View child = mTabLayout.getChildAt(i); final boolean isSelected = i == position; child.setSelected(isSelected); if (isSelected) { animateToTab(position); if (mFirstBuildTab) { ((TabView)child).twsShowIndicatorViewEnd(); } else { if (!ActionBar.mIsInActionMode) ((TabView)child).twsShowIndicatorView(); else ((TabView)child).twsShowIndicatorViewEnd(); } } else { ((TabView)child).twsHideIndicatorViewEnd(); } } } public void setContentHeight(int contentHeight) { mContentHeight = contentHeight; requestLayout(); } private class TabLayout extends LinearLayout { public TabLayout(Context context) { this(context, null); } public TabLayout(Context context, AttributeSet attrs) { //这里暂时不替换 this(context, attrs, com.android.internal.R.attr.actionBarTabBarStyle); } public TabLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mIndicator != null && mInit && mDrawIndicator) { mIndicator.setBounds(mIndicatorRect.left, mIndicatorRect.top, mIndicatorRect.right, mIndicatorRect.bottom); mIndicator.draw(canvas); } } }; private LinearLayout createTabLayout() { int attrId = ResIdentifierUtils.getSysAttrId("actionBarTabBarStyle"); final LinearLayout tabLayout = new TabLayout(getContext(), null, attrId == 0 ? com.android.internal.R.attr.actionBarTabBarStyle : attrId); tabLayout.setMeasureWithLargestChildEnabled(true); tabLayout.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); return tabLayout; } private class TabRelativeLayout extends RelativeLayout { public TabRelativeLayout(Context context) { this(context, null); } public TabRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } public TabRelativeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mIndicator != null && mInit && mDrawIndicator) { mIndicator.setBounds(mIndicatorRect.left, mIndicatorRect.top, mIndicatorRect.right, mIndicatorRect.bottom); mIndicator.draw(canvas); } } }; private RelativeLayout createTabRelativeLayout() { final RelativeLayout tabLayout = new TabRelativeLayout(getContext()); tabLayout.setLayoutParams(new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.MATCH_PARENT)); return tabLayout; } private LinearLayout createTabInternalLayout() { int attrId = ResIdentifierUtils.getSysAttrId("actionBarTabBarStyle"); final LinearLayout tabLayout = new LinearLayout(getContext(), null, attrId == 0 ? com.android.internal.R.attr.actionBarTabBarStyle : attrId); tabLayout.setMeasureWithLargestChildEnabled(true); tabLayout.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); return tabLayout; } private Spinner createSpinner() { int attrId = ResIdentifierUtils.getSysAttrId("actionDropDownStyle"); final Spinner spinner = new Spinner(getContext(), null, attrId == 0 ? com.android.internal.R.attr.actionDropDownStyle : attrId); spinner.setLayoutParams(new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); spinner.setOnItemSelectedListener(this); return spinner; } @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); int attrId = ResIdentifierUtils.getSysAttrId("actionBarStyle"); TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.ActionBar, attrId == 0 ? com.android.internal.R.attr.actionBarStyle : attrId, 0); setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0)); setTabContentHeight(mTabMode); a.recycle(); } public void animateToVisibility(int visibility) { if (mVisibilityAnim != null) { mVisibilityAnim.cancel(); } if (visibility == VISIBLE) { if (getVisibility() != VISIBLE) { setAlpha(0); } ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1); anim.setDuration(FADE_DURATION); anim.setInterpolator(sAlphaInterpolator); anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); anim.start(); } else { ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0); anim.setDuration(FADE_DURATION); anim.setInterpolator(sAlphaInterpolator); anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); anim.start(); } } public void animateToTab(final int position) { final View tabView = mTabLayout.getChildAt(position); if (mTabSelector != null) { removeCallbacks(mTabSelector); } mTabSelector = new Runnable() { public void run() { // final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2; // smoothScrollTo(scrollPos, 0); mTabSelector = null; } }; post(mTabSelector); } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); if (mTabSelector != null) { // Re-post the selector we saved post(mTabSelector); } } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mTabSelector != null) { removeCallbacks(mTabSelector); } } private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) { final TabView tabView = new TabView(getContext(), tab, forAdapter); if (forAdapter) { if (android.os.Build.VERSION.SDK_INT > 15) { tabView.setBackground(null); } else { tabView.setBackgroundDrawable(null); } tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, mContentHeight)); } else { tabView.setFocusable(true); if (mTabClickListener == null) { mTabClickListener = new TabClickListener(); } tabView.setOnClickListener(mTabClickListener); } return tabView; } public void enableTabClick(boolean enable) { final int tabCount = mTabLayout.getChildCount(); for (int i = 0; i < tabCount; i++) { final View child = mTabLayout.getChildAt(i); child.setClickable(enable); } } public void addTab(ActionBar.Tab tab, boolean setSelected) { TabView tabView = createTabView(tab, false); mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1)); if (mTabSpinner != null) { ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); } if (setSelected) { tabView.setSelected(true); } if (mAllowCollapse) { requestLayout(); } } public void addTabInternal(ActionBar.Tab tab, boolean setSelected) { TabView tabView = createTabView(tab, false); mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1)); if (mTabSpinner != null) { ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); } if (setSelected) { tabView.setSelected(true); } if (mAllowCollapse) { requestLayout(); } } public void addTabLayout() { RelativeLayout.LayoutParams params0 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); params0.addRule(RelativeLayout.ALIGN_PARENT_LEFT); if (mLeftView != null) { mTabOutLayout.addView(mLeftView, params0); if (mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY) { mLeftView.setPadding(0, TwsActivity.getStatusBarHeight(), 0, 0); } mLeftView.measure(0, 0); } RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); params1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); if (mRightView != null) { mTabOutLayout.addView(mRightView, params1); if (mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY) { mRightView.setPadding(0, TwsActivity.getStatusBarHeight(), 0, 0); } mRightView.measure(0, 0); } final int screenWidth = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth(); int leftViewWidth = 0; int rightViewWidth = 0; if (mLeftView != null) { leftViewWidth = mLeftView.getMeasuredWidth(); } else { leftViewWidth = (int) getResources().getDimension(R.dimen.tws_tab_customview_minwidth); } if (mRightView != null) { rightViewWidth = mRightView.getMeasuredWidth(); } else { rightViewWidth = (int) getResources().getDimension(R.dimen.tws_tab_customview_minwidth); } RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams((screenWidth-leftViewWidth-rightViewWidth), LayoutParams.MATCH_PARENT); params2.addRule(RelativeLayout.CENTER_IN_PARENT); if (mTabLayout != null) { mTabOutLayout.addView(mTabLayout, params2); } } public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { final TabView tabView = createTabView(tab, false); mTabLayout.addView(tabView, position, new LinearLayout.LayoutParams( 0, LayoutParams.MATCH_PARENT, 1)); if (mTabSpinner != null) { ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); } if (setSelected) { tabView.setSelected(true); } if (mAllowCollapse) { requestLayout(); } } public void updateTab(int position) { ((TabView) mTabLayout.getChildAt(position)).update(); if (mTabSpinner != null) { ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); } if (mAllowCollapse) { requestLayout(); } } public void removeTabAt(int position) { mTabLayout.removeViewAt(position); if (mTabSpinner != null) { ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); } if (mAllowCollapse) { requestLayout(); } } public void removeAllTabs() { mTabLayout.removeAllViews(); if (mTabSpinner != null) { ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); } if (mAllowCollapse) { requestLayout(); } } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { TabView tabView = (TabView) view; tabView.getTab().select(); } @Override public void onNothingSelected(AdapterView<?> parent) { } public boolean onTouchEvent(MotionEvent arg0) { // TODO Auto-generated method stub return false; } public void twsSetPageSelected(int position) { final TabView beforeTabView = (TabView)(mTabLayout.getChildAt(mBeforeTabPostion)); final TabView afterTabView = (TabView)(mTabLayout.getChildAt(position)); if (!mHasPageScrolled && !ActionBar.mIsInActionMode) { if (!mFirstBuildTab) { mWaveView.setAmplitude(5); } beforeTabView.twsHideIndicatorView(); afterTabView.twsShowIndicatorView(); mHasPageSelected = true; mPageSelectedNeedReset = true; } mBeforeTabPostion = position; } // tws-start add smooth scroll feature to tab::2014-11-18 public void twsSetPageScroll(int position, float positionOffset) { if (mTabLayout == null) return; final int tabCount = mTabLayout.getChildCount(); //check illege sate if (positionOffset < 0 || positionOffset > 1) return; if( mSelectedTabIndex < 0 || mSelectedTabIndex > tabCount - 1) return; if( position < 0 || position > tabCount - 1 ) return; //illege state end if (positionOffset == 0.0 || positionOffset == 1.0 || position == tabCount - 1) { cancelScrollState(); if (mFirstBuildTab) { mWaveView.setAmplitude(0); mFirstBuildTab = false; } else { if (mWScrollCnt != 0 || mPageSelectedNeedReset) { if (!mAMAnimator.isRunning()) mAMAnimator.start(); mPageSelectedNeedReset = false; } } mWScrollCnt = 0; return; } mWScrollCnt++; final TabView selectedTabView = (TabView)(mTabLayout.getChildAt(mSelectedTabIndex)); int normalIndex = 0; if (normalIndex == mSelectedTabIndex) normalIndex = 1; final TabView normalTabView = (TabView)(mTabLayout.getChildAt(normalIndex)); if ( mInit == false) { //mIndicator = getResources().getDrawable(R.drawable.tab_selected_holo); if (selectedTabView.getBackground() != null) { if ( selectedTabView.getBackground() instanceof StateListDrawable ) { //mIndicator = selectedTabView.getBackground().getCurrent(); int index = ((StateListDrawable)selectedTabView.getBackground()).getStateDrawableIndex(new int[]{android.R.attr.state_selected}); mIndicator = ((StateListDrawable)selectedTabView.getBackground()).getStateDrawable(index); } else mIndicator = selectedTabView.getBackground(); } if (mTabTextSelectChange) { mSelectedColor = selectedTabView.twsGetTextColor(); mNormalColor = normalTabView.twsGetTextColor(); mNormalColors = normalTabView.twsGetTextColors(); } mInit = true; } final TabView leftTabView = (TabView)(mTabLayout.getChildAt(position)); final TabView rightTabView = (TabView)(mTabLayout.getChildAt(position + 1)); if( mDrawableDepot.isEmpty() || tabCount != mDrawableDepot.size() ) { mDrawableDepot.clear(); for (int i = 0; i < tabCount; i++) { TabView child = (TabView)mTabLayout.getChildAt(i); mDrawableDepot.add(child.getBackground()); } } if (mTabTextSelectChange) { float la = ((float)( (mSelectedColor >> 24) & 0xFF )) * (1 - positionOffset) + ((float)((mNormalColor >> 24) & 0xFF)) * positionOffset; float lr = ((float) ( (mSelectedColor >> 16) & 0xFF )) * (1 - positionOffset) + ((float)((mNormalColor >> 16) & 0xFF)) * positionOffset; float lg = ((float)( (mSelectedColor >> 8) & 0xFF )) * (1 - positionOffset) + ((float)((mNormalColor >> 8) & 0xFF)) * positionOffset; float lb = ((float)( (mSelectedColor >> 0) & 0xFF )) * (1 - positionOffset) + ((float)((mNormalColor >> 0) & 0xFF)) * positionOffset; float ra = ((float)( (mSelectedColor >> 24) & 0xFF )) * positionOffset + ((float)((mNormalColor >> 24) & 0xFF)) * (1 - positionOffset) ; float rr = ((float)( (mSelectedColor >> 16) & 0xFF )) * positionOffset + ((float)((mNormalColor >> 16) & 0xFF)) * (1 - positionOffset) ; float rg = ((float)( (mSelectedColor >> 8) & 0xFF )) * positionOffset + ((float)((mNormalColor >> 8) & 0xFF)) * (1 - positionOffset) ; float rb = ((float)( (mSelectedColor >> 0) & 0xFF )) * positionOffset + ((float)((mNormalColor >> 0) & 0xFF)) * (1 - positionOffset) ; leftTabView.twsSetTextColor(android.graphics.Color.argb((int)la, (int)lr, (int)lg, (int)lb)); rightTabView.twsSetTextColor(android.graphics.Color.argb((int)ra, (int)rr, (int)rg, (int)rb)); } if (!mHasPageSelected) { if (mWScrollCnt < 16 && mWScrollCnt % 3 == 0) { mWaveView.setAmplitude(mAmplitude++); } leftTabView.twsSetIndicatorAlpha(1.0f-positionOffset); rightTabView.twsSetIndicatorAlpha(positionOffset); leftTabView.twsSetIndicatorTransY(mAnimEnd+mIndicatorViewOffset*positionOffset); rightTabView.twsSetIndicatorTransY(mAnimStart-mIndicatorViewOffset*positionOffset); mHasPageScrolled = true; } float leftX = leftTabView.getX(); float leftY = leftTabView.getY(); int leftWidth = leftTabView.getWidth(); int leftHeight = leftTabView.getHeight(); float rightX = rightTabView.getX(); float rightY = rightTabView.getY(); int rightWidth = rightTabView.getWidth(); int rightHeight = rightTabView.getHeight(); mIndicatorRect.left = (int)(leftX * (1.0 - positionOffset) + rightX * positionOffset); mIndicatorRect.top = (int)(leftY + rightY) / 2; mIndicatorRect.right = (int)((leftX + (float)leftWidth) * (1.0 - positionOffset) + (rightX + (float)rightWidth) * positionOffset); mIndicatorRect.bottom = mIndicatorRect.top + (leftHeight + rightHeight) / 2; mTabLayout.invalidate(); if (android.os.Build.VERSION.SDK_INT > 15) { leftTabView.setBackground(null); rightTabView.setBackground(null); } else { leftTabView.setBackgroundDrawable(null); rightTabView.setBackgroundDrawable(null); } mDrawIndicator = true; } public void twsSetScrollEnd() { cancelScrollState(); } private void cancelScrollState( ) { final int tabCount = mTabLayout.getChildCount(); for (int i = 0; i < tabCount; i++) { final TabView child = (TabView)mTabLayout.getChildAt(i); if (child != null) { if (mTabTextSelectChange) { child.twsSetTextColors(mNormalColors); } if ( i < mDrawableDepot.size() ) { if (android.os.Build.VERSION.SDK_INT > 15) { child.setBackground((Drawable)mDrawableDepot.get(i)); } else { child.setBackgroundDrawable((Drawable)mDrawableDepot.get(i)); } child.refreshDrawableState(); if (i == mSelectedTabIndex) { child.setSelected(false); child.setSelected(true); if (!mHasPageSelected) { child.twsSetIndicatorTransY(mAnimEnd); child.twsSetIndicatorAlpha(1.0f); } } else { child.setSelected(true); child.setSelected(false); if (!mHasPageSelected) { child.twsSetIndicatorTransY(mAnimStart); child.twsSetIndicatorAlpha(0.0f); } } } } } mDrawableDepot.clear(); mDrawIndicator = false; mHasPageScrolled = false; mHasPageSelected = false; mAmplitude = 0; mTabLayout.invalidate(); } // tws-end add smooth scroll feature to tab ::2014-11-18 private class TabView extends FrameLayout { private ActionBar.Tab mTab; private TextView mTextView; private ImageView mIconView; private View mCustomView; private ImageView mIndicatorView; private AnimatorSet mShowIndicatorAnim, mHideIndicatorAnim; private AnimatorListener mShowIndicatorListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { enableTabClick(true); if (mIndicatorView != null) { mIndicatorView.setTranslationY(mAnimEnd); mIndicatorView.setAlpha(1.0f); if (!mAMAnimator.isRunning() && !mFirstBuildTab && mWaveView.getAmplitude() == 5) { mAMAnimator.start(); } } } }; private AnimatorListener mHideIndicatorListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { enableTabClick(true); if (mIndicatorView != null) { mIndicatorView.setTranslationY(mAnimStart); mIndicatorView.setAlpha(0.0f); if (!mAMAnimator.isRunning() && !mFirstBuildTab && mWaveView.getAmplitude() == 5) { mAMAnimator.start(); } } } }; public TabView(Context context, ActionBar.Tab tab, boolean forList) { super(context, null, ((mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY_SECOND ||mTabMode == ActionBar.ACTIONBAR_TAB_STANDARD_SECOND) ? R.attr.actionBarSubTabStyle : R.attr.actionBarTabStyle)); mTab = tab; if (forList) { // setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); } update(); } public int twsGetTextColor() { if (mTextView == null) return 0; return mTextView.getCurrentTextColor(); } public ColorStateList twsGetTextColors() { if (mTextView == null) return null; return mTextView.getTextColors(); } public void twsSetTextColor(int color) { if (mTextView == null) return; mTextView.setTextColor(color); } public void twsSetTextColors(ColorStateList colors) { if (mTextView == null || colors == null) return; mTextView.setTextColor(colors); } public void twsShowIndicatorView() { if (mIndicatorView == null) { return; } if (mIndicatorView.getTranslationY() < mAnimStart && mIndicatorView.getTranslationY() > mAnimEnd) { return; } if (mShowIndicatorAnim != null && mShowIndicatorAnim.isRunning() && !mFirstBuildTab) { enableTabClick(false); return; } if (mShowIndicatorAnim == null) { mShowIndicatorAnim = new AnimatorSet(); } AnimatorSet.Builder b = mShowIndicatorAnim.play(ObjectAnimator.ofFloat(mIndicatorView, "alpha", 0, 1)); b.with(ObjectAnimator.ofFloat(mIndicatorView, "translationY", mAnimStart, mAnimEnd)); mShowIndicatorAnim.setDuration(300); mShowIndicatorAnim.start(); mShowIndicatorAnim.addListener(mShowIndicatorListener); } public void twsHideIndicatorView() { if (mIndicatorView == null) { return; } if (mIndicatorView.getTranslationY() < mAnimStart && mIndicatorView.getTranslationY() > mAnimEnd) { return; } if (mHideIndicatorAnim != null && mHideIndicatorAnim.isRunning() && !mFirstBuildTab) { enableTabClick(false); return; } if (mHideIndicatorAnim == null) { mHideIndicatorAnim = new AnimatorSet(); } AnimatorSet.Builder b = mHideIndicatorAnim.play(ObjectAnimator.ofFloat(mIndicatorView, "alpha",1, 0)); b.with(ObjectAnimator.ofFloat(mIndicatorView, "translationY",mAnimEnd, mAnimStart)); mHideIndicatorAnim.setDuration(300); mHideIndicatorAnim.start(); mHideIndicatorAnim.addListener(mHideIndicatorListener); } public void twsShowIndicatorViewEnd() { mShowIndicatorListener.onAnimationEnd(null); } public void twsHideIndicatorViewEnd() { mHideIndicatorListener.onAnimationEnd(null); } public void twsSetIndicatorTransY(float transY) { if (mIndicatorView == null) return; mIndicatorView.setTranslationY(transY); } public void twsSetIndicatorAlpha(float alpha) { if (mIndicatorView == null) return; mIndicatorView.setAlpha(alpha); } public void bindTab(ActionBar.Tab tab) { mTab = tab; update(); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Re-measure if we went beyond our maximum size. if (mMaxTabWidth > 0 && getMeasuredWidth() > mMaxTabWidth) { super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxTabWidth, MeasureSpec.EXACTLY), heightMeasureSpec); } } public void update() { final ActionBar.Tab tab = mTab; final View custom = tab.getCustomView(); if (custom != null) { final ViewParent customParent = custom.getParent(); if (customParent != this) { if (customParent != null) ((ViewGroup) customParent).removeView(custom); addView(custom); } mCustomView = custom; if (mTextView != null) mTextView.setVisibility(GONE); if (mIconView != null) { mIconView.setVisibility(GONE); mIconView.setImageDrawable(null); } } else { if (mCustomView != null) { removeView(mCustomView); mCustomView = null; } final Drawable icon = tab.getIcon(); final CharSequence text = tab.getText(); if (icon != null) { if (mIconView == null) { ImageView iconView = new ImageView(getContext()); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER_VERTICAL; iconView.setLayoutParams(lp); addView(iconView, 0); mIconView = iconView; } mIconView.setImageDrawable(icon); mIconView.setVisibility(VISIBLE); } else if (mIconView != null) { mIconView.setVisibility(GONE); mIconView.setImageDrawable(null); } if (text != null) { if (mTextView == null) { TextView textView = null; if (mTabMode == ActionBar.ACTIONBAR_TAB_OVERLAY_SECOND ||mTabMode == ActionBar.ACTIONBAR_TAB_STANDARD_SECOND) { textView = new TextView(getContext(), null, R.attr.actionBarSubTabTextStyle); } else { textView = new TextView(getContext(), null, R.attr.actionBarTabTextStyle); } addView(textView); mTextView = textView; } mTextView.setText(text); mTextView.setVisibility(VISIBLE); } else if (mTextView != null) { mTextView.setVisibility(GONE); mTextView.setText(null); } ImageView indicator = new ImageView(getContext()); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER_HORIZONTAL; indicator.setLayoutParams(lp); indicator.setImageDrawable(getResources().getDrawable(R.drawable.tab_wave_indicator)); indicator.setTranslationY(mAnimStart); indicator.setAlpha(0.0f); addView(indicator); if (mActionBarTabThemeWave && mActionBarTabTheme == ThemeUtils.ACTIONBARTAB_THEME_WAVE) { mIndicatorView = indicator; } if (mIconView != null) { mIconView.setContentDescription(tab.getContentDescription()); } } } public ActionBar.Tab getTab() { return mTab; } } private class TabAdapter extends BaseAdapter { @Override public int getCount() { return mTabLayout.getChildCount(); } @Override public Object getItem(int position) { return ((TabView) mTabLayout.getChildAt(position)).getTab(); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = createTabView((ActionBar.Tab) getItem(position), true); } else { ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position)); } return convertView; } } private class TabClickListener implements OnClickListener { public void onClick(View view) { TabView tabView = (TabView) view; tabView.getTab().select(); final int tabCount = mTabLayout.getChildCount(); for (int i = 0; i < tabCount; i++) { final View child = mTabLayout.getChildAt(i); child.setSelected(child == view); } } } protected class VisibilityAnimListener implements Animator.AnimatorListener { private boolean mCanceled = false; private int mFinalVisibility; public VisibilityAnimListener withFinalVisibility(int visibility) { mFinalVisibility = visibility; return this; } @Override public void onAnimationStart(Animator animation) { setVisibility(VISIBLE); mVisibilityAnim = animation; mCanceled = false; } @Override public void onAnimationEnd(Animator animation) { if (mCanceled) return; mVisibilityAnim = null; setVisibility(mFinalVisibility); } @Override public void onAnimationCancel(Animator animation) { mCanceled = true; } @Override public void onAnimationRepeat(Animator animation) { } } public void setTabContentHeight(int tabMode) { int height = 0; switch (tabMode) { case ActionBar.ACTIONBAR_TAB_STANDARD: if (getResources().getBoolean(R.bool.config_statusbar_state)) { if (mTabWaveEnable) { height = (int) getContext().getResources().getDimension(R.dimen.tws_action_bar_tab_height); } else { height = (int) getContext().getResources().getDimension(R.dimen.tws_action_bar_height) + TwsActivity.getStatusBarHeight(); } } else { height = (int) getContext().getResources().getDimension(R.dimen.tws_action_bar_height); } setContentHeight(height); break; case ActionBar.ACTIONBAR_TAB_OVERLAY: if (mTabWaveEnable) { height = (int) getContext().getResources().getDimension(R.dimen.tws_action_bar_tab_height); } else { height = (int) getContext().getResources().getDimension(R.dimen.tws_action_bar_height); } setContentHeight(height); break; case ActionBar.ACTIONBAR_TAB_OVERLAY_SECOND: case ActionBar.ACTIONBAR_TAB_STANDARD_SECOND: height = (int) getContext().getResources().getDimension(R.dimen.tws_action_bar_tab_second_height); setContentHeight(height); break; default: break; } } public int getTabMode(){ return mTabMode; } public void setStackedDrawable(Drawable drawable) { mWaveView.setStackedDrawable(drawable); } public boolean getTabWaveEnable() { return mTabWaveEnable; } public void twsSetTabTextSelectChange(boolean change) { mTabTextSelectChange = change; } public void twsSetTabLeftView(View view) { mLeftView = view; } public void twsSetTabRightView(View view) { mRightView = view; } public void twsSetTabCustomEnd() { if (mTabButtonEnable && mTabOutLayout.getChildCount() == 0) { addTabLayout(); } } private static final IntProperty<HorizontalWaveView> AM_VALUE = new IntProperty<HorizontalWaveView>("amValue") { @Override public void setValue(HorizontalWaveView object, int value) { object.setAmplitude(value); } @Override public Integer get(HorizontalWaveView object) { return null; } }; }