| /* |
| * Copyright (C) 2013 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.google.reviewit.widget; |
| |
| import android.R; |
| import android.content.Context; |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.Paint; |
| import android.util.AttributeSet; |
| import android.util.TypedValue; |
| import android.view.View; |
| import android.widget.LinearLayout; |
| |
| class SlidingTabStrip 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 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 int mBottomBorderThickness; |
| private final Paint mBottomBorderPaint; |
| |
| private int mSelectedIndicatorThickness; |
| private final Paint mSelectedIndicatorPaint; |
| |
| private final int mDefaultBottomBorderColor; |
| |
| private final Paint mDividerPaint; |
| private final float mDividerHeight; |
| |
| private int mSelectedPosition; |
| private float mSelectionOffset; |
| |
| private SlidingTabLayout.TabColorizer mCustomTabColorizer; |
| private final SimpleTabColorizer mDefaultTabColorizer; |
| |
| SlidingTabStrip(Context context) { |
| this(context, null); |
| } |
| |
| SlidingTabStrip(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| setWillNotDraw(false); |
| |
| final float density = getResources().getDisplayMetrics().density; |
| |
| TypedValue outValue = new TypedValue(); |
| context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true); |
| final int themeForegroundColor = outValue.data; |
| |
| mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, |
| DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); |
| |
| mDefaultTabColorizer = new SimpleTabColorizer(); |
| mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR); |
| mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, |
| DEFAULT_DIVIDER_COLOR_ALPHA)); |
| |
| mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); |
| mBottomBorderPaint = new Paint(); |
| mBottomBorderPaint.setColor(mDefaultBottomBorderColor); |
| |
| mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); |
| mSelectedIndicatorPaint = new Paint(); |
| |
| mDividerHeight = DEFAULT_DIVIDER_HEIGHT; |
| mDividerPaint = new Paint(); |
| mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density)); |
| } |
| |
| void setCustomTabColorizer(SlidingTabLayout.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 setBorderColor(int color) { |
| mBottomBorderPaint.setColor(color); |
| invalidate(); |
| } |
| |
| void setBottomBorderThickness(int bottomBorderThickness) { |
| mBottomBorderThickness = bottomBorderThickness; |
| invalidate(); |
| } |
| |
| void setSelectedIndicatorThickness(int selectedIndicatorThickness) { |
| mSelectedIndicatorThickness = selectedIndicatorThickness; |
| invalidate(); |
| } |
| |
| void onViewPagerPageChanged(int position, float positionOffset) { |
| mSelectedPosition = position; |
| mSelectionOffset = positionOffset; |
| invalidate(); |
| } |
| |
| @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 SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null |
| ? mCustomTabColorizer |
| : mDefaultTabColorizer; |
| |
| // 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); |
| |
| 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 |
| View nextTitle = getChildAt(mSelectedPosition + 1); |
| left = (int) (mSelectionOffset * nextTitle.getLeft() + |
| (1.0f - mSelectionOffset) * left); |
| right = (int) (mSelectionOffset * nextTitle.getRight() + |
| (1.0f - mSelectionOffset) * right); |
| } |
| |
| mSelectedIndicatorPaint.setColor(color); |
| |
| canvas.drawRect(left, height - mSelectedIndicatorThickness, right, |
| height, mSelectedIndicatorPaint); |
| } |
| |
| // 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 SlidingTabLayout.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; |
| } |
| } |
| } |