/* * Copyright (c) 2015 [1076559197@qq.com | tchen0707@gmail.com] * * 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.dreamspace.uucampus.widget.smartlayout; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.LinearLayout; import com.dreamspace.uucampus.R; /** * <p> * Forked from Google Samples > SlidingTabsBasic > * <a href="https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html">SlidingTabStrip</a> */ class SmartTabStrip extends LinearLayout { private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8; private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5; private static final float DEFAULT_INDICATOR_CORNER_RADIUS = 0f; private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f; private static final boolean DEFAULT_INDICATOR_IN_CENTER = false; private static final boolean DEFAULT_INDICATOR_IN_FRONT = false; private final int mBottomBorderThickness; private final Paint mBottomBorderPaint; private final RectF mIndicatorRectF = new RectF(); private final boolean mIndicatorAlwaysInCenter; private final boolean mIndicatorInFront; private final int mIndicatorThickness; private final float mIndicatorCornerRadius; private final Paint mIndicatorPaint; private final Paint mDividerPaint; private final float mDividerHeight; private int mLastPosition; private int mSelectedPosition; private float mSelectionOffset; private SmartTabIndicationInterpolator mIndicationInterpolator; private SmartTabLayout.TabColorizer mCustomTabColorizer; private final SimpleTabColorizer mDefaultTabColorizer; SmartTabStrip(Context context, AttributeSet attrs) { super(context); setWillNotDraw(false); final float density = getResources().getDisplayMetrics().density; TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true); final int themeForegroundColor = outValue.data; boolean indicatorInFront = DEFAULT_INDICATOR_IN_FRONT; boolean indicatorAlwaysInCenter = DEFAULT_INDICATOR_IN_CENTER; int indicationInterpolatorId = SmartTabIndicationInterpolator.ID_SMART; int indicatorColor = DEFAULT_SELECTED_INDICATOR_COLOR; int indicatorColorsId = NO_ID; int indicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); float indicatorCornerRadius = DEFAULT_INDICATOR_CORNER_RADIUS * density; int underlineColor = setColorAlpha(themeForegroundColor, DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); int underlineThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); int dividerColor = setColorAlpha(themeForegroundColor, DEFAULT_DIVIDER_COLOR_ALPHA); int dividerColorsId = NO_ID; int dividerThickness = (int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.stl_SmartTabLayout); indicatorAlwaysInCenter = a.getBoolean(R.styleable.stl_SmartTabLayout_stl_indicatorAlwaysInCenter, indicatorAlwaysInCenter); indicatorInFront = a.getBoolean(R.styleable.stl_SmartTabLayout_stl_indicatorInFront, indicatorInFront); indicationInterpolatorId = a.getInt(R.styleable.stl_SmartTabLayout_stl_indicatorInterpolation, indicationInterpolatorId); indicatorColor = a.getColor(R.styleable.stl_SmartTabLayout_stl_indicatorColor, indicatorColor); indicatorColorsId = a.getResourceId(R.styleable.stl_SmartTabLayout_stl_indicatorColors, indicatorColorsId); indicatorThickness = a.getDimensionPixelSize(R.styleable.stl_SmartTabLayout_stl_indicatorThickness, indicatorThickness); indicatorCornerRadius = a.getDimension(R.styleable.stl_SmartTabLayout_stl_indicatorCornerRadius, indicatorCornerRadius); underlineColor = a.getColor(R.styleable.stl_SmartTabLayout_stl_underlineColor, underlineColor); underlineThickness = a.getDimensionPixelSize(R.styleable.stl_SmartTabLayout_stl_underlineThickness, underlineThickness); dividerColor = a.getColor(R.styleable.stl_SmartTabLayout_stl_dividerColor, dividerColor); dividerColorsId = a.getResourceId(R.styleable.stl_SmartTabLayout_stl_dividerColors, dividerColorsId); dividerThickness = a.getDimensionPixelSize(R.styleable.stl_SmartTabLayout_stl_dividerThickness, dividerThickness); a.recycle(); final int[] indicatorColors = (indicatorColorsId == NO_ID) ? new int[] { indicatorColor } : getResources().getIntArray(indicatorColorsId); final int[] dividerColors = (dividerColorsId == NO_ID) ? new int[] { dividerColor } : getResources().getIntArray(dividerColorsId); mDefaultTabColorizer = new SimpleTabColorizer(); mDefaultTabColorizer.setIndicatorColors(indicatorColors); mDefaultTabColorizer.setDividerColors(dividerColors); mBottomBorderThickness = underlineThickness; mBottomBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBottomBorderPaint.setColor(underlineColor); mIndicatorAlwaysInCenter = indicatorAlwaysInCenter; mIndicatorInFront = indicatorInFront; mIndicatorThickness = indicatorThickness; mIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mIndicatorCornerRadius = indicatorCornerRadius; mDividerHeight = DEFAULT_DIVIDER_HEIGHT; mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mDividerPaint.setStrokeWidth(dividerThickness); mIndicationInterpolator = SmartTabIndicationInterpolator.of(indicationInterpolatorId); } void setIndicationInterpolator(SmartTabIndicationInterpolator interpolator) { mIndicationInterpolator = interpolator; invalidate(); } void setCustomTabColorizer(SmartTabLayout.TabColorizer customTabColorizer) { mCustomTabColorizer = customTabColorizer; invalidate(); } void setSelectedIndicatorColors(int... colors) { // Make sure that the custom colorizer is removed mCustomTabColorizer = null; mDefaultTabColorizer.setIndicatorColors(colors); invalidate(); } void setDividerColors(int... colors) { // Make sure that the custom colorizer is removed mCustomTabColorizer = null; mDefaultTabColorizer.setDividerColors(colors); invalidate(); } void onViewPagerPageChanged(int position, float positionOffset) { mSelectedPosition = position; mSelectionOffset = positionOffset; if (positionOffset == 0f && mLastPosition != mSelectedPosition) { mLastPosition = mSelectedPosition; } invalidate(); } boolean isIndicatorAlwaysInCenter() { return mIndicatorAlwaysInCenter; } int getChildMeasuredWidthAt(int index) { return getChildAt(index).getMeasuredWidth(); } int getChildWidthAt(int index) { return getChildAt(index).getWidth(); } @Override protected void onDraw(Canvas canvas) { final int height = getHeight(); final int childCount = getChildCount(); final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height); final SmartTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null ? mCustomTabColorizer : mDefaultTabColorizer; if (mIndicatorInFront) { // Thin underline along the entire bottom edge canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); } // Thick colored underline below the current selection if (childCount > 0) { View selectedTitle = getChildAt(mSelectedPosition); int left = selectedTitle.getLeft(); int right = selectedTitle.getRight(); int color = tabColorizer.getIndicatorColor(mSelectedPosition); float thickness = mIndicatorThickness; if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); if (color != nextColor) { color = blendColors(nextColor, color, mSelectionOffset); } // Draw the selection partway between the tabs float leftOffset = mIndicationInterpolator.getLeftEdge(mSelectionOffset); float rightOffset = mIndicationInterpolator.getRightEdge(mSelectionOffset); float thicknessOffset = mIndicationInterpolator.getThickness(mSelectionOffset); View nextTitle = getChildAt(mSelectedPosition + 1); left = (int) (leftOffset * nextTitle.getLeft() + (1.0f - leftOffset) * left); right = (int) (rightOffset * nextTitle.getRight() + (1.0f - rightOffset) * right); thickness = thickness * thicknessOffset; } mIndicatorPaint.setColor(color); mIndicatorRectF.set( left, height - (mIndicatorThickness / 2f) - (thickness / 2f), right, height - (mIndicatorThickness / 2f) + (thickness / 2f)); if (mIndicatorCornerRadius > 0f) { canvas.drawRoundRect( mIndicatorRectF, mIndicatorCornerRadius, mIndicatorCornerRadius, mIndicatorPaint); } else { canvas.drawRect(mIndicatorRectF, mIndicatorPaint); } } if (!mIndicatorInFront) { // Thin underline along the entire bottom edge canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); } // Vertical separators between the titles int separatorTop = (height - dividerHeightPx) / 2; for (int i = 0; i < childCount - 1; i++) { View child = getChildAt(i); mDividerPaint.setColor(tabColorizer.getDividerColor(i)); canvas.drawLine(child.getRight(), separatorTop, child.getRight(), separatorTop + dividerHeightPx, mDividerPaint); } } /** * Set the alpha value of the {@code color} to be the given {@code alpha} value. */ private static int setColorAlpha(int color, byte alpha) { return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); } /** * Blend {@code color1} and {@code color2} using the given ratio. * * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, * 0.0 will return {@code color2}. */ private static int blendColors(int color1, int color2, float ratio) { final float inverseRation = 1f - ratio; float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); return Color.rgb((int) r, (int) g, (int) b); } private static class SimpleTabColorizer implements SmartTabLayout.TabColorizer { private int[] mIndicatorColors; private int[] mDividerColors; @Override public final int getIndicatorColor(int position) { return mIndicatorColors[position % mIndicatorColors.length]; } @Override public final int getDividerColor(int position) { return mDividerColors[position % mDividerColors.length]; } void setIndicatorColors(int... colors) { mIndicatorColors = colors; } void setDividerColors(int... colors) { mDividerColors = colors; } } }