Java tutorial
/* * Copyright (C) 2014 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 am.widget.indicatortabstrip; import android.annotation.TargetApi; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.annotation.ColorInt; import android.support.annotation.ColorRes; import android.support.annotation.DrawableRes; import android.support.v4.content.ContextCompat; import am.widget.basetabstrip.BaseTabStrip; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPager; import android.text.TextPaint; import android.util.AttributeSet; /** * TabStripItem?5 * * @author Alex */ @ViewPager.DecorView public class IndicatorTabStrip extends BaseTabStrip { private static final int[] ATTRS = new int[] { android.R.attr.textSize, android.R.attr.textColor, android.R.attr.divider }; private static final int DEFAULT_TEXT_SIZE = 14;// ?dp private static final int DEFAULT_TEXT_COLOR = 0xff000000;// private static final int DEFAULT_ITEM_WIDTH = 64;// ??dp private static final int DEFAULT_ITEM_HEIGHT = 32;// ??dp private static final int DEFAULT_TAG_TEXT_SIZE = 11;// Tag?dp private static final int DEFAULT_TAG_TEXT_COLOR = 0xffffffff;// Tag private static final int DEFAULT_TAG_MIN_SIZE = 15;// Tag??dp public static final int INDICATOR_WIDTH_MODE_SET = 0;// public static final int INDICATOR_WIDTH_MODE_TAB = 1;// ? public static final int INDICATOR_WIDTH_BY_DRAWABLE = -1;// public static final int INDICATOR_HEIGHT_BY_DRAWABLE = -1;// public static final int TAG_MIN_SIZE_MODE_HAS_TEXT = 0;// ?? public static final int TAG_MIN_SIZE_MODE_ALWAYS = 1;// ? private final TextPaint mTextPaint;// private float mTextSize;// ? private float mTextDesc;// ?? private ColorStateList mTextColor;// private float mTextScale;// private ColorStateList mGradient;// ??? private Drawable mDivider;// Divider private Drawable mIndicator;// private int mIndicatorWidthMode;// ? private int mIndicatorPadding;// Padding??? private int mIndicatorWidth;// private int mIndicatorHeight;// private Drawable mInterval;// ? private int mMinItemWidth;// ?? private int mMinItemHeight;// ?? private ItemTabAdapter mAdapter;// Tag private float mTagTextSize;// Tag? private float mTagTextDesc;// Tag?? private int mTagTextColor;// Tag private Drawable mTagBackground;// Tag private int mTagMinSizeMode;// Tag?? private int mTagMinWidth;// Tag? private int mTagMinHeight;// Tag? private TagLocation mTagLocation;// Tag private Rect mTextMeasureBounds = new Rect();// ? private int mCurrentPager = 0; private int mNextPager = 0; private float mOffset = 1; public IndicatorTabStrip(Context context) { this(context, null); } public IndicatorTabStrip(Context context, AttributeSet attrs) { this(context, attrs, 0); } public IndicatorTabStrip(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setItemClickable(true); setClickSmoothScroll(true); final float density = getResources().getDisplayMetrics().density; mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setTextAlign(Align.CENTER); if (Build.VERSION.SDK_INT > 4) { updateTextPaintDensity(); } mTagLocation = new TagLocation(TagLocation.LOCATION_EDGE); final TypedArray a = context.obtainStyledAttributes(attrs, ATTRS); int n = a.getIndexCount(); int textSize = (int) (DEFAULT_TEXT_SIZE * density); ColorStateList textColors = null; Drawable divider = null; for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case 0: textSize = a.getDimensionPixelSize(attr, textSize); break; case 1: textColors = a.getColorStateList(attr); break; case 2: divider = a.getDrawable(attr); break; } } a.recycle(); float scale = 1; Drawable itemBackground = null; ColorStateList gradient = null; Drawable indicator = null; int indicatorWidthMode = INDICATOR_WIDTH_MODE_SET; int indicatorPadding = 0; int indicatorWidth = INDICATOR_WIDTH_BY_DRAWABLE; int indicatorHeight = INDICATOR_HEIGHT_BY_DRAWABLE; Drawable interval = null; int minItemWidth = (int) (DEFAULT_ITEM_WIDTH * density); int minItemHeight = (int) (DEFAULT_ITEM_HEIGHT * density); int tagTextSize = (int) (DEFAULT_TAG_TEXT_SIZE * density); int tagTextColor = DEFAULT_TAG_TEXT_COLOR; Drawable tagBackground = getDefaultTagBackground(); int tagMinSizeMode = TAG_MIN_SIZE_MODE_HAS_TEXT; int tagMinWidth = (int) (DEFAULT_TAG_MIN_SIZE * density); int tagMinHeight = (int) (DEFAULT_TAG_MIN_SIZE * density); int tagPaddingLeft = 0; int tagPaddingTop = 0; int tagPaddingRight = 0; int tagPaddingBottom = 0; int tagMarginLeft = 0; int tagMarginTop = 0; int tagMarginRight = 0; int tagMarginBottom = 0; TypedArray custom = context.obtainStyledAttributes(attrs, R.styleable.IndicatorTabStrip); textSize = custom.getDimensionPixelSize(R.styleable.IndicatorTabStrip_ttsTextSize, textSize); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsTextColor)) textColors = custom.getColorStateList(R.styleable.IndicatorTabStrip_ttsTextColor); scale = custom.getFloat(R.styleable.IndicatorTabStrip_ttsTextScale, scale); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsBackground)) itemBackground = custom.getDrawable(R.styleable.IndicatorTabStrip_ttsBackground); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsGradient)) gradient = custom.getColorStateList(R.styleable.IndicatorTabStrip_ttsGradient); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsDivider)) divider = custom.getDrawable(R.styleable.IndicatorTabStrip_ttsDivider); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsIndicator)) indicator = custom.getDrawable(R.styleable.IndicatorTabStrip_ttsIndicator); indicatorWidthMode = custom.getInt(R.styleable.IndicatorTabStrip_ttsIndicatorWidthMode, indicatorWidthMode); indicatorPadding = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsIndicatorPadding, indicatorPadding); indicatorWidth = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsIndicatorWidth, indicatorWidth); indicatorHeight = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsIndicatorHeight, indicatorHeight); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsInterval)) interval = custom.getDrawable(R.styleable.IndicatorTabStrip_ttsInterval); minItemWidth = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsMinItemWidth, minItemWidth); minItemHeight = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsMinItemHeight, minItemHeight); tagTextSize = custom.getDimensionPixelSize(R.styleable.IndicatorTabStrip_ttsTagTextSize, tagTextSize); tagTextColor = custom.getColor(R.styleable.IndicatorTabStrip_ttsTagTextColor, tagTextColor); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsTagBackground)) tagBackground = custom.getDrawable(R.styleable.IndicatorTabStrip_ttsTagBackground); tagMinSizeMode = custom.getInt(R.styleable.IndicatorTabStrip_ttsTagMinSizeMode, tagMinSizeMode); tagMinWidth = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMinWidth, tagMinWidth); tagMinHeight = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMinHeight, tagMinHeight); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsTagPadding)) { final int padding = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagPadding, 0); tagPaddingLeft = padding; tagPaddingTop = padding; tagPaddingRight = padding; tagPaddingBottom = padding; } tagPaddingLeft = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagPaddingLeft, tagPaddingLeft); tagPaddingTop = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagPaddingTop, tagPaddingTop); tagPaddingRight = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagPaddingRight, tagPaddingRight); tagPaddingBottom = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagPaddingBottom, tagPaddingBottom); if (custom.hasValue(R.styleable.IndicatorTabStrip_ttsTagMargin)) { final int margin = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMargin, 0); tagMarginLeft = margin; tagMarginTop = margin; tagMarginRight = margin; tagMarginBottom = margin; } tagMarginLeft = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMarginLeft, tagMarginLeft); tagMarginTop = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMarginTop, tagMarginTop); tagMarginRight = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMarginRight, tagMarginRight); tagMarginBottom = custom.getDimensionPixelOffset(R.styleable.IndicatorTabStrip_ttsTagMarginBottom, tagMarginBottom); custom.recycle(); setTextSize(textSize); if (textColors != null) { setTextColor(textColors); } else { setTextColor(DEFAULT_TEXT_COLOR); } setTextScale(scale); setItemBackground(itemBackground); setGradient(gradient); setDivider(divider); setIndicator(indicator); setIndicatorWidthMode(indicatorWidthMode); setIndicatorPadding(indicatorPadding); setIndicatorWidth(indicatorWidth); setIndicatorHeight(indicatorHeight); setInterval(interval); setMinItemWidth(minItemWidth); setMinItemHeight(minItemHeight); setTagTextSize(tagTextSize); setTagTextColor(tagTextColor); setTagBackground(tagBackground); setTagMinSizeMode(tagMinSizeMode); setTagMinWidth(tagMinWidth); setTagMinHeight(tagMinHeight); setTagPadding(tagPaddingLeft, tagPaddingTop, tagPaddingRight, tagPaddingBottom); setTagMargin(tagMarginLeft, tagMarginTop, tagMarginRight, tagMarginBottom); } @TargetApi(5) private void updateTextPaintDensity() { mTextPaint.density = getResources().getDisplayMetrics().density; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mTextPaint.setTextSize(mTextSize); Paint.FontMetricsInt metrics = mTextPaint.getFontMetricsInt(); final int textHeight = metrics.bottom - metrics.top; mTextDesc = metrics.bottom; int textWidth = 0; for (int i = 0; i < getItemCount(); i++) { if (getItemText(i) != null) { String text = getItemText(i).toString(); mTextPaint.getTextBounds(text, 0, text.length(), mTextMeasureBounds); textWidth = Math.max(textWidth, mTextMeasureBounds.width()); } } final int maxTextWidth = mTextScale > 1 ? (int) (Math.ceil((float) textWidth * mTextScale) + 1) : textWidth; final int itemBackgroundWith = getMinItemBackgroundWidth(); final int itemWidth = Math.max(maxTextWidth, Math.max(mMinItemWidth, itemBackgroundWith)); final int intervalWidth = getIntervalWidth(); final int totalWidth = itemWidth * getItemCount() + intervalWidth * (getItemCount() - 1) + ViewCompat.getPaddingStart(this) + ViewCompat.getPaddingEnd(this); final int dividerWidth = mDivider == null ? 0 : mDivider.getIntrinsicWidth() + ViewCompat.getPaddingStart(this) + ViewCompat.getPaddingEnd(this); final int width = Math.max(Math.max(totalWidth, dividerWidth), getSuggestedMinimumWidth()); final int maxTextHeight = mTextScale > 1 ? (int) (Math.ceil((float) textHeight * mTextScale) + 1) : textHeight; final int itemBackgroundHeight = getMinItemBackgroundHeight(); final int intervalHeight = mInterval == null ? 0 : mInterval.getIntrinsicHeight(); final int dividerHeight = getDividerHeight(); final int itemHeight = Math.max(Math.max(maxTextHeight, intervalHeight), Math.max(mMinItemHeight, itemBackgroundHeight)); final int height = Math.max(dividerHeight + itemHeight + getPaddingTop() + getPaddingBottom(), getSuggestedMinimumHeight()); setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); mTextPaint.setTextSize(mTagTextSize); metrics = mTextPaint.getFontMetricsInt(); mTagTextDesc = metrics.bottom; } /** * ? * * @return */ protected int getIntervalWidth() { return mInterval == null ? 0 : mInterval.getIntrinsicWidth(); } /** * ?? * * @return ? */ protected float getItemWidth() { float width = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this) - getIntervalWidth() * (getItemCount() - 1); return width / getItemCount(); } /** * ??? * * @return ?? */ protected int getDrawItemWidth() { return Math.round(getItemWidth()); } /** * ???? * * @return ??? */ protected int getLastItemWidth() { return getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this) - getIntervalWidth() * (getItemCount() - 1) - getDrawItemWidth() * (getItemCount() - 1); } /** * ?Divider * * @return Divider */ protected int getDividerHeight() { return mDivider == null ? 0 : mDivider.getIntrinsicHeight(); } /** * ?? * * @return ? */ protected int getItemHeight() { return getHeight() - getDividerHeight() - getPaddingTop() - getPaddingBottom(); } @Override protected void jumpTo(int current) { mCurrentPager = current - 1; mNextPager = current; mOffset = 1; invalidate(); } @Override protected void gotoLeft(int current, int next, float offset) { mCurrentPager = current; mNextPager = next; mOffset = 1 - offset; invalidate(); } @Override protected void gotoRight(int current, int next, float offset) { mCurrentPager = current; mNextPager = next; mOffset = offset; invalidate(); } @Override protected int pointToPosition(float x, float y) { final int paddingTop = getPaddingTop(); final int paddingBottom = getPaddingBottom(); if (y < paddingTop || y > getWidth() - paddingBottom) { return -1; } int position = -1; final float itemWidth = getItemWidth(); final int intervalWidth = getIntervalWidth(); for (int i = 0; i < getItemCount(); i++) { float l = ViewCompat.getPaddingStart(this) + intervalWidth * i + itemWidth * i; float r = l + itemWidth; if (x >= l && x <= r) { position = i; break; } } return position; } @Override protected float getHotspotX(Drawable background, int position, float motionX, float motionY) { return motionX - getPaddingLeft() - getIntervalWidth() * position - getItemWidth() * position; } @Override protected float getHotspotY(Drawable background, int position, float motionX, float motionY) { return motionY; } @Override protected int getItemCount() { if (isInEditMode()) { return 3; } return super.getItemCount(); } @Override protected CharSequence getItemText(int position) { if (isInEditMode()) { return "Tab" + position; } return super.getItemText(position); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawDivider(canvas); drawItem(canvas); drawIndicator(canvas); } /** * Divider * * @param canvas */ protected void drawDivider(Canvas canvas) { if (mDivider == null || mDivider.getIntrinsicHeight() <= 0) return; final int dividerWidth = mDivider.getIntrinsicWidth() > 0 ? mDivider.getIntrinsicWidth() : getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this); final int dividerHeight = mDivider.getIntrinsicHeight(); mDivider.setBounds(0, 0, dividerWidth, dividerHeight); final float moveX = ViewCompat.getPaddingStart(this); final float moveY = getItemHeight() + getPaddingTop(); canvas.save(); canvas.translate(moveX, moveY); mDivider.draw(canvas); canvas.restore(); } /** * ? * * @param canvas */ protected void drawItem(Canvas canvas) { final int itemWidth = getDrawItemWidth(); final int itemHeight = getItemHeight(); for (int position = 0; position < getItemCount(); position++) { drawItemBackground(canvas, position, itemWidth, itemHeight); drawItemGradient(canvas, position, itemWidth, itemHeight); drawInterval(canvas, position, itemWidth, itemHeight); drawText(canvas, position, itemWidth, itemHeight); drawTag(canvas, position, itemWidth, itemHeight); } } /** * * * @param canvas * @param position ??? * @param itemWidth ? * @param itemHeight ? */ protected void drawItemBackground(Canvas canvas, int position, int itemWidth, int itemHeight) { if (!hasItemBackgrounds()) return; Drawable tag = getItemBackground(position); if (position == getItemCount() - 1) { int restWidth = getLastItemWidth(); tag.setBounds(0, 0, restWidth, itemHeight); } else { tag.setBounds(0, 0, itemWidth, itemHeight); } final float moveX = ViewCompat.getPaddingStart(this) + (itemWidth + getIntervalWidth()) * position; final float moveY = getPaddingTop(); canvas.save(); canvas.translate(moveX, moveY); tag.draw(canvas); canvas.restore(); } /** * ?? * * @param canvas * @param position ??? * @param itemWidth ? * @param itemHeight ? */ protected void drawItemGradient(Canvas canvas, int position, int itemWidth, int itemHeight) { if (mGradient == null || !mGradient.isStateful()) return; final int normalColor = mGradient.getDefaultColor(); final int selectedColor = mGradient.getColorForState(SELECTED_STATE_SET, normalColor); if (position == mNextPager) { mTextPaint.setColor(getColor(normalColor, selectedColor, mOffset)); } else if (position == mCurrentPager) { mTextPaint.setColor(getColor(normalColor, selectedColor, 1 - mOffset)); } else { mTextPaint.setColor(normalColor); } final float moveX = ViewCompat.getPaddingStart(this) + (itemWidth + getIntervalWidth()) * position; final float moveY = getPaddingTop(); final int restWidth = position == getItemCount() - 1 ? getLastItemWidth() : itemWidth; canvas.save(); canvas.translate(moveX, moveY); canvas.drawRect(0, 0, restWidth, itemHeight, mTextPaint); canvas.restore(); } /** * * * @param canvas * @param position ??? * @param itemWidth ? * @param itemHeight ? */ protected void drawInterval(Canvas canvas, int position, int itemWidth, int itemHeight) { if (mInterval == null || mInterval.getIntrinsicWidth() <= 0 || position == getItemCount() - 1) return; final int intervalHeight = mInterval.getIntrinsicHeight() <= 0 ? itemHeight : mInterval.getIntrinsicHeight(); mInterval.setBounds(0, 0, getIntervalWidth(), intervalHeight); final int moveX = ViewCompat.getPaddingStart(this) + itemWidth * position; final float moveY = getPaddingTop() + (itemHeight - intervalHeight) * 0.5f; canvas.save(); canvas.translate(moveX, moveY); mInterval.draw(canvas); canvas.restore(); } /** * * * @param canvas * @param position ??? * @param itemWidth ? * @param itemHeight ? */ protected void drawText(Canvas canvas, int position, int itemWidth, int itemHeight) { if (getItemText(position) == null) return; String text = getItemText(position).toString(); if (text.length() <= 0) return; mTextPaint.setTextSize(mTextSize); if (mTextColor == null) { mTextPaint.setColor(DEFAULT_TEXT_COLOR); } else { final int normalColor = mTextColor.getDefaultColor(); final int selectedColor = mTextColor.getColorForState(SELECTED_STATE_SET, normalColor); if (position == mNextPager) { mTextPaint.setColor(getColor(normalColor, selectedColor, mOffset)); } else if (position == mCurrentPager) { mTextPaint.setColor(getColor(normalColor, selectedColor, 1 - mOffset)); } else { mTextPaint.setColor(normalColor); } } final float centerX = ViewCompat.getPaddingStart(this) + (itemWidth + getIntervalWidth()) * ((float) position + 0.5f); final float centerY = getPaddingTop() + itemHeight * 0.5f; float scale; if (position == mNextPager) { scale = 1 + (mTextScale - 1) * mOffset; } else if (position == mCurrentPager) { scale = 1 + (mTextScale - 1) * (1 - mOffset); } else { scale = 1; } canvas.save(); canvas.translate(centerX, centerY + mTextDesc); if (scale != 1) { canvas.scale(scale, scale, 0, -mTextDesc); } canvas.drawText(text, 0, 0, mTextPaint); canvas.restore(); } /** * Tag * * @param canvas * @param position ??? * @param itemWidth ? * @param itemHeight ? */ @SuppressWarnings("unused") protected void drawTag(Canvas canvas, int position, int itemWidth, int itemHeight) { if (mAdapter == null || !mAdapter.isTagEnable(position)) return; String text = mAdapter.getTag(position) == null ? "" : mAdapter.getTag(position); mTextPaint.setTextSize(mTagTextSize); mTextPaint.setColor(mTagTextColor); mTextPaint.getTextBounds(text, 0, text.length(), mTextMeasureBounds); final int textWidth = mTextMeasureBounds.width(); final int textHeight = mTextMeasureBounds.height(); final int tagBackgroundWidth = mTagBackground == null ? 0 : mTagBackground.getIntrinsicWidth(); final int tagBackgroundHeight = mTagBackground == null ? 0 : mTagBackground.getIntrinsicHeight(); int tagWidth; int tagHeight; switch (mTagMinSizeMode) { default: case TAG_MIN_SIZE_MODE_HAS_TEXT: if ("".equals(text)) { tagWidth = Math.min(mTagMinWidth, tagBackgroundWidth); tagHeight = Math.min(mTagMinHeight, tagBackgroundHeight); break; } case TAG_MIN_SIZE_MODE_ALWAYS: tagWidth = Math.max(textWidth + mTagLocation.getPaddingLeft() + mTagLocation.getPaddingRight(), Math.max(mTagMinWidth, tagBackgroundWidth)); tagHeight = Math.max(textHeight + mTagLocation.getPaddingTop() + mTagLocation.getPaddingBottom(), Math.max(mTagMinHeight, tagBackgroundHeight)); break; } final int rightTabX = position == getItemCount() - 1 ? getWidth() - ViewCompat.getPaddingEnd(this) : ViewCompat.getPaddingStart(this) + (itemWidth + getIntervalWidth()) * position + itemWidth; final int rightTagX = rightTabX - mTagLocation.getMarginRight(); final int tagY = getPaddingTop() + mTagLocation.getMarginTop(); final int leftTagX = rightTagX - tagWidth; final float tagCenterX = leftTagX + tagWidth * 0.5f; final float tagCenterY = tagY + tagWidth * 0.5f; canvas.save(); if (mTagBackground != null) { mTagBackground.setBounds(0, 0, tagWidth, tagHeight); canvas.translate(leftTagX, tagY); mTagBackground.draw(canvas); if (!"".equals(text)) { canvas.translate(tagWidth * 0.5f, tagHeight * 0.5f + mTagTextDesc); canvas.drawText(text, 0, 0, mTextPaint); } } else { canvas.translate(tagCenterX, tagCenterY + mTagTextDesc); canvas.drawText(text, 0, 0, mTextPaint); } canvas.restore(); } /** * * * @param canvas */ protected void drawIndicator(Canvas canvas) { if (mIndicator == null) return; final int indicatorWidth = getIndicatorWidth(); final int indicatorHeight = getIndicatorHeight(); if (indicatorWidth <= 0 || indicatorHeight <= 0) return; mIndicator.setBounds(0, 0, indicatorWidth, indicatorHeight); final float widthWithInterval = getItemWidth() + getIntervalWidth(); final float currentCenter = ViewCompat.getPaddingStart(this) + mCurrentPager * widthWithInterval + widthWithInterval * 0.5f; final float nextCenter = ViewCompat.getPaddingStart(this) + mNextPager * widthWithInterval + widthWithInterval * 0.5f; final float moveCenter = currentCenter + (nextCenter - currentCenter) * mOffset; final float moveX = moveCenter - indicatorWidth * 0.5f; final float moveY = getHeight() - getPaddingBottom() - getDividerHeight() - indicatorHeight; canvas.save(); canvas.translate(moveX, moveY); mIndicator.draw(canvas); canvas.restore(); } /** * ?? * * @return ? */ @SuppressWarnings("unused") public float getTextSize() { return mTextSize; } /** * ? * * @param size ? */ public void setTextSize(float size) { if (mTextSize != size) { mTextSize = size; requestLayout(); invalidate(); } } /** * ? * * @return */ @SuppressWarnings("unused") public ColorStateList getTextColor() { return mTextColor; } /** * * * @param color */ public void setTextColor(ColorStateList color) { if (color != null && color != mTextColor) { mTextColor = color; invalidate(); } } /** * * * @param color */ public void setTextColor(@ColorInt int color) { setTextColor(ColorStateList.valueOf(color)); } /** * ? * * @return */ @SuppressWarnings("unused") public float getTextScale() { return mTextScale; } /** * * * @param scale */ public void setTextScale(float scale) { if (scale > 0 && mTextScale != scale) { mTextScale = scale; requestLayout(); invalidate(); } } /** * ??? * * @return ?? */ @SuppressWarnings("unused") public ColorStateList getGradient() { return mGradient; } /** * ?? * * @param gradient ?? */ public void setGradient(ColorStateList gradient) { if (gradient == null) { mGradient = null; invalidate(); } else if (mGradient != gradient && gradient.isStateful()) { mGradient = gradient; invalidate(); } else { setItemBackground(new ColorDrawable(gradient.getDefaultColor())); } } /** * ?? * * @param gradient ?? */ @SuppressWarnings("unused") public void setGradient(@ColorRes int gradient) { setGradient(ContextCompat.getColorStateList(getContext(), gradient)); } /** * ?Divider * * @return Divider */ @SuppressWarnings("unused") public Drawable getDivider() { return mDivider; } /** * Divider * * @param divider Divider */ public void setDivider(Drawable divider) { if (mDivider != divider) { mDivider = divider; invalidate(); } } /** * Divider * * @param divider Divider */ @SuppressWarnings("unused") public void setDivider(@DrawableRes int divider) { setDivider(ContextCompat.getDrawable(getContext(), divider)); } /** * ? * * @return */ @SuppressWarnings("unused") public Drawable getIndicator() { return mIndicator; } /** * * * @param indicator */ public void setIndicator(Drawable indicator) { if (mIndicator != indicator) { mIndicator = indicator; invalidate(); } } /** * * * @param indicator */ @SuppressWarnings("unused") public void setIndicator(@DrawableRes int indicator) { setIndicator(ContextCompat.getDrawable(getContext(), indicator)); } /** * ?? * * @return ? */ @SuppressWarnings("unused") public int getIndicatorWidthMode() { return mIndicatorWidthMode; } /** * ?? * * @param mode ?? */ public void setIndicatorWidthMode(int mode) { if (mode != INDICATOR_WIDTH_MODE_SET && mode != INDICATOR_WIDTH_MODE_TAB) return; if (mIndicatorWidthMode != mode) { mIndicatorWidthMode = mode; invalidate(); } } /** * ?Padding * * @return Padding */ @SuppressWarnings("unused") public int getIndicatorPadding() { return mIndicatorPadding; } /** * Padding * * @param padding Padding */ public void setIndicatorPadding(int padding) { if (mIndicatorPadding != padding) { mIndicatorPadding = padding; invalidate(); } } /** * ? * * @return */ public int getIndicatorWidth() { if (mIndicator == null) return 0; switch (mIndicatorWidthMode) { default: case INDICATOR_WIDTH_MODE_SET: return mIndicatorWidth == INDICATOR_WIDTH_BY_DRAWABLE ? mIndicator.getIntrinsicWidth() : mIndicatorWidth; case INDICATOR_WIDTH_MODE_TAB: return getDrawItemWidth() - mIndicatorPadding * 2; } } /** * * * @param width */ public void setIndicatorWidth(int width) { if (width < INDICATOR_WIDTH_BY_DRAWABLE) return; if (mIndicatorWidth != width) { mIndicatorWidth = width; invalidate(); } } /** * ? * * @return */ public int getIndicatorHeight() { if (mIndicator == null) return 0; return mIndicatorHeight == INDICATOR_HEIGHT_BY_DRAWABLE ? mIndicator.getIntrinsicHeight() : mIndicatorHeight; } /** * * * @param height */ public void setIndicatorHeight(int height) { if (height < INDICATOR_HEIGHT_BY_DRAWABLE) return; if (mIndicatorHeight != height) { mIndicatorHeight = height; invalidate(); } } /** * ?? * * @return ? */ @SuppressWarnings("unused") public Drawable getInterval() { return mInterval; } /** * ? * * @param interval ? */ public void setInterval(Drawable interval) { if (mInterval != interval) { mInterval = interval; invalidate(); } } /** * ? * * @param interval ? */ @SuppressWarnings("unused") public void setInterval(@DrawableRes int interval) { setInterval(ContextCompat.getDrawable(getContext(), interval)); } /** * ??? * * @return ?? */ @SuppressWarnings("unused") public int getMinItemWidth() { return mMinItemWidth; } /** * ?? * * @param width ?? */ public void setMinItemWidth(int width) { if (width >= 0 && width != mMinItemWidth) { mMinItemWidth = width; requestLayout(); invalidate(); } } /** * ??? * * @return ?? */ @SuppressWarnings("unused") public int getMinItemHeight() { return mMinItemHeight; } /** * ?? * * @param height ?? */ public void setMinItemHeight(int height) { if (height >= 0 && height != mMinItemHeight) { mMinItemHeight = height; requestLayout(); invalidate(); } } /** * ?Adapter * * @return Adapter */ @SuppressWarnings("unused") public ItemTabAdapter getAdapter() { return mAdapter; } /** * Adapter * * @param adapter Adapter */ public void setAdapter(ItemTabAdapter adapter) { if (mAdapter != adapter) { mAdapter = adapter; invalidate(); } } /** * ?Tag? * * @return Tag? */ @SuppressWarnings("unused") public float getTagTextSize() { return mTagTextSize; } /** * Tag? * * @param size Tag? */ public void setTagTextSize(float size) { if (mTagTextSize != size) { mTagTextSize = size; invalidate(); } } /** * ?Tag * * @return Tag */ @SuppressWarnings("unused") public int getTagTextColor() { return mTagTextColor; } /** * Tag * * @param color Tag */ public void setTagTextColor(@ColorInt int color) { if (mTagTextColor != color) { mTagTextColor = color; invalidate(); } } /** * ?Tag * * @return Tag */ @SuppressWarnings("unused") public Drawable getTagBackground() { return mTagBackground; } /** * Tag * * @param background Tag */ public void setTagBackground(Drawable background) { if (mTagBackground != background) { mTagBackground = background; invalidate(); } } /** * Tag * * @param background Tag */ @SuppressWarnings("unused") public void setTagBackground(@DrawableRes int background) { setTagBackground(ContextCompat.getDrawable(getContext(), background)); } /** * ?Tag?? * * @return Tag?? */ @SuppressWarnings("unused") public int getTagMinSizeMode() { return mTagMinSizeMode; } /** * Tag?? * * @param mode Tag?? */ public void setTagMinSizeMode(int mode) { if (mode != TAG_MIN_SIZE_MODE_HAS_TEXT && mode != TAG_MIN_SIZE_MODE_ALWAYS) return; if (mTagMinSizeMode != mode) { mTagMinSizeMode = mode; invalidate(); } } /** * ?Tag? * * @return Tag? */ @SuppressWarnings("unused") public int getTagMinWidth() { return mTagMinWidth; } /** * Tag? * * @param width Tag? */ public void setTagMinWidth(int width) { if (width >= 0 && mTagMinWidth != width) { mTagMinWidth = width; invalidate(); } } /** * ?Tag? * * @return Tag? */ @SuppressWarnings("unused") public int getTagMinHeight() { return mTagMinHeight; } /** * Tag? * * @param height Tag? */ public void setTagMinHeight(int height) { if (height >= 0 && mTagMinHeight != height) { mTagMinHeight = height; invalidate(); } } /** * Tag Padding * * @param left * @param top * @param right ? * @param bottom */ public void setTagPadding(int left, int top, int right, int bottom) { if (mTagLocation.setPadding(left, top, right, bottom)) { invalidate(); } } /** * Tag Margin * * @param left * @param top * @param right ? * @param bottom */ public void setTagMargin(int left, int top, int right, int bottom) { if (mTagLocation.setMargin(left, top, right, bottom)) { invalidate(); } } }