空格
This commit is contained in:
1
moduletablayout/.gitignore
vendored
Normal file
1
moduletablayout/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
35
moduletablayout/build.gradle
Normal file
35
moduletablayout/build.gradle
Normal file
@@ -0,0 +1,35 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'com.example.moduletablayout'
|
||||
compileSdk 35
|
||||
|
||||
defaultConfig {
|
||||
minSdk 24
|
||||
targetSdk 35
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation libs.appcompat
|
||||
implementation libs.material
|
||||
testImplementation libs.junit
|
||||
androidTestImplementation libs.ext.junit
|
||||
androidTestImplementation libs.espresso.core
|
||||
}
|
||||
21
moduletablayout/proguard-rules.pro
vendored
Normal file
21
moduletablayout/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
4
moduletablayout/src/main/AndroidManifest.xml
Normal file
4
moduletablayout/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.example.moduletablayout">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,964 @@
|
||||
package com.example.moduletablayout;
|
||||
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
|
||||
import com.example.moduletablayout.listener.CustomTabEntity;
|
||||
import com.example.moduletablayout.listener.OnTabSelectListener;
|
||||
import com.example.moduletablayout.utils.FragmentChangeManager;
|
||||
import com.example.moduletablayout.utils.UnreadMsgUtils;
|
||||
import com.example.moduletablayout.widget.MsgView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** 没有继承HorizontalScrollView不能滑动,对于ViewPager无依赖 */
|
||||
public class CommonTabLayout extends FrameLayout implements ValueAnimator.AnimatorUpdateListener {
|
||||
private Context mContext;
|
||||
private ArrayList<CustomTabEntity> mTabEntitys = new ArrayList<>();
|
||||
private LinearLayout mTabsContainer;
|
||||
private int mCurrentTab;
|
||||
private int mLastTab;
|
||||
private int mTabCount;
|
||||
/** 用于绘制显示器 */
|
||||
private Rect mIndicatorRect = new Rect();
|
||||
private GradientDrawable mIndicatorDrawable = new GradientDrawable();
|
||||
|
||||
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Path mTrianglePath = new Path();
|
||||
private static final int STYLE_NORMAL = 0;
|
||||
private static final int STYLE_TRIANGLE = 1;
|
||||
private static final int STYLE_BLOCK = 2;
|
||||
private int mIndicatorStyle = STYLE_NORMAL;
|
||||
|
||||
private float mTabPadding;
|
||||
private boolean mTabSpaceEqual;
|
||||
private float mTabWidth;
|
||||
|
||||
/** indicator */
|
||||
private int mIndicatorColor;
|
||||
private float mIndicatorHeight;
|
||||
private float mIndicatorWidth;
|
||||
private float mIndicatorCornerRadius;
|
||||
private float mIndicatorMarginLeft;
|
||||
private float mIndicatorMarginTop;
|
||||
private float mIndicatorMarginRight;
|
||||
private float mIndicatorMarginBottom;
|
||||
private long mIndicatorAnimDuration;
|
||||
private boolean mIndicatorAnimEnable;
|
||||
private boolean mIndicatorBounceEnable;
|
||||
private int mIndicatorGravity;
|
||||
|
||||
/** underline */
|
||||
private int mUnderlineColor;
|
||||
private float mUnderlineHeight;
|
||||
private int mUnderlineGravity;
|
||||
|
||||
/** divider */
|
||||
private int mDividerColor;
|
||||
private float mDividerWidth;
|
||||
private float mDividerPadding;
|
||||
|
||||
/** title */
|
||||
private static final int TEXT_BOLD_NONE = 0;
|
||||
private static final int TEXT_BOLD_WHEN_SELECT = 1;
|
||||
private static final int TEXT_BOLD_BOTH = 2;
|
||||
private float mTextsize;
|
||||
private int mTextSelectColor;
|
||||
private int mTextUnselectColor;
|
||||
private int mTextBold;
|
||||
private boolean mTextAllCaps;
|
||||
|
||||
/** icon */
|
||||
private boolean mIconVisible;
|
||||
private int mIconGravity;
|
||||
private float mIconWidth;
|
||||
private float mIconHeight;
|
||||
private float mIconMargin;
|
||||
|
||||
private int mHeight;
|
||||
|
||||
/** anim */
|
||||
private ValueAnimator mValueAnimator;
|
||||
private OvershootInterpolator mInterpolator = new OvershootInterpolator(1.5f);
|
||||
|
||||
private FragmentChangeManager mFragmentChangeManager;
|
||||
|
||||
public CommonTabLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public CommonTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CommonTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
|
||||
this.mContext = context;
|
||||
mTabsContainer = new LinearLayout(context);
|
||||
addView(mTabsContainer);
|
||||
|
||||
obtainAttributes(context, attrs);
|
||||
|
||||
//get layout_height
|
||||
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
|
||||
|
||||
//create ViewPager
|
||||
if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) {
|
||||
} else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) {
|
||||
} else {
|
||||
int[] systemAttrs = {android.R.attr.layout_height};
|
||||
@SuppressLint("ResourceType") TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
|
||||
mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP);
|
||||
mValueAnimator.addUpdateListener(this);
|
||||
}
|
||||
|
||||
private void obtainAttributes(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CommonTabLayout);
|
||||
|
||||
mIndicatorStyle = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_style, 0);
|
||||
mIndicatorColor = ta.getColor(R.styleable.CommonTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff"));
|
||||
mIndicatorHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_height,
|
||||
dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2)));
|
||||
mIndicatorWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1));
|
||||
mIndicatorCornerRadius = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0));
|
||||
mIndicatorMarginLeft = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_left, dp2px(0));
|
||||
mIndicatorMarginTop = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorMarginRight = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_right, dp2px(0));
|
||||
mIndicatorMarginBottom = ta.getDimension(R.styleable.CommonTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorAnimEnable = ta.getBoolean(R.styleable.CommonTabLayout_tl_indicator_anim_enable, true);
|
||||
mIndicatorBounceEnable = ta.getBoolean(R.styleable.CommonTabLayout_tl_indicator_bounce_enable, true);
|
||||
mIndicatorAnimDuration = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_anim_duration, -1);
|
||||
mIndicatorGravity = ta.getInt(R.styleable.CommonTabLayout_tl_indicator_gravity, Gravity.BOTTOM);
|
||||
|
||||
mUnderlineColor = ta.getColor(R.styleable.CommonTabLayout_tl_underline_color, Color.parseColor("#ffffff"));
|
||||
mUnderlineHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_underline_height, dp2px(0));
|
||||
mUnderlineGravity = ta.getInt(R.styleable.CommonTabLayout_tl_underline_gravity, Gravity.BOTTOM);
|
||||
|
||||
mDividerColor = ta.getColor(R.styleable.CommonTabLayout_tl_divider_color, Color.parseColor("#ffffff"));
|
||||
mDividerWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_divider_width, dp2px(0));
|
||||
mDividerPadding = ta.getDimension(R.styleable.CommonTabLayout_tl_divider_padding, dp2px(12));
|
||||
|
||||
mTextsize = ta.getDimension(R.styleable.CommonTabLayout_tl_textsize, sp2px(13f));
|
||||
mTextSelectColor = ta.getColor(R.styleable.CommonTabLayout_tl_textSelectColor, Color.parseColor("#ffffff"));
|
||||
mTextUnselectColor = ta.getColor(R.styleable.CommonTabLayout_tl_textUnselectColor, Color.parseColor("#AAffffff"));
|
||||
mTextBold = ta.getInt(R.styleable.CommonTabLayout_tl_textBold, TEXT_BOLD_NONE);
|
||||
mTextAllCaps = ta.getBoolean(R.styleable.CommonTabLayout_tl_textAllCaps, false);
|
||||
|
||||
mIconVisible = ta.getBoolean(R.styleable.CommonTabLayout_tl_iconVisible, true);
|
||||
mIconGravity = ta.getInt(R.styleable.CommonTabLayout_tl_iconGravity, Gravity.TOP);
|
||||
mIconWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_iconWidth, dp2px(0));
|
||||
mIconHeight = ta.getDimension(R.styleable.CommonTabLayout_tl_iconHeight, dp2px(0));
|
||||
mIconMargin = ta.getDimension(R.styleable.CommonTabLayout_tl_iconMargin, dp2px(2.5f));
|
||||
|
||||
mTabSpaceEqual = ta.getBoolean(R.styleable.CommonTabLayout_tl_tab_space_equal, true);
|
||||
mTabWidth = ta.getDimension(R.styleable.CommonTabLayout_tl_tab_width, dp2px(-1));
|
||||
mTabPadding = ta.getDimension(R.styleable.CommonTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(10));
|
||||
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
public void setTabData(ArrayList<CustomTabEntity> tabEntitys) {
|
||||
if (tabEntitys == null || tabEntitys.size() == 0) {
|
||||
throw new IllegalStateException("TabEntitys can not be NULL or EMPTY !");
|
||||
}
|
||||
|
||||
this.mTabEntitys.clear();
|
||||
this.mTabEntitys.addAll(tabEntitys);
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/** 关联数据支持同时切换fragments */
|
||||
public void setTabData(ArrayList<CustomTabEntity> tabEntitys, FragmentActivity fa, int containerViewId, ArrayList<Fragment> fragments) {
|
||||
mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments);
|
||||
setTabData(tabEntitys);
|
||||
}
|
||||
|
||||
/** 更新数据 */
|
||||
public void notifyDataSetChanged() {
|
||||
mTabsContainer.removeAllViews();
|
||||
this.mTabCount = mTabEntitys.size();
|
||||
View tabView;
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
if (mIconGravity == Gravity.LEFT) {
|
||||
tabView = View.inflate(mContext, R.layout.layout_tab_left, null);
|
||||
} else if (mIconGravity == Gravity.RIGHT) {
|
||||
tabView = View.inflate(mContext, R.layout.layout_tab_right, null);
|
||||
} else if (mIconGravity == Gravity.BOTTOM) {
|
||||
tabView = View.inflate(mContext, R.layout.layout_tab_bottom, null);
|
||||
} else {
|
||||
tabView = View.inflate(mContext, R.layout.layout_tab_top, null);
|
||||
}
|
||||
|
||||
tabView.setTag(i);
|
||||
addTab(i, tabView);
|
||||
}
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
/** 创建并添加tab */
|
||||
private void addTab(final int position, View tabView) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
tv_tab_title.setText(mTabEntitys.get(position).getTabTitle());
|
||||
ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);
|
||||
iv_tab_icon.setImageResource(mTabEntitys.get(position).getTabUnselectedIcon());
|
||||
|
||||
tabView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = (Integer) v.getTag();
|
||||
if (mCurrentTab != position) {
|
||||
setCurrentTab(position);
|
||||
if (mListener != null) {
|
||||
mListener.onTabSelect(position);
|
||||
}
|
||||
} else {
|
||||
if (mListener != null) {
|
||||
mListener.onTabReselect(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** 每一个Tab的布局参数 */
|
||||
LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?
|
||||
new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
|
||||
new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
if (mTabWidth > 0) {
|
||||
lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
mTabsContainer.addView(tabView, position, lp_tab);
|
||||
}
|
||||
|
||||
private void updateTabStyles() {
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor);
|
||||
tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize);
|
||||
// tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
|
||||
if (mTextAllCaps) {
|
||||
tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase());
|
||||
}
|
||||
|
||||
if (mTextBold == TEXT_BOLD_BOTH) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(true);
|
||||
} else if (mTextBold == TEXT_BOLD_NONE) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(false);
|
||||
}
|
||||
|
||||
ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);
|
||||
if (mIconVisible) {
|
||||
iv_tab_icon.setVisibility(View.VISIBLE);
|
||||
CustomTabEntity tabEntity = mTabEntitys.get(i);
|
||||
iv_tab_icon.setImageResource(i == mCurrentTab ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon());
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
mIconWidth <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconWidth,
|
||||
mIconHeight <= 0 ? LinearLayout.LayoutParams.WRAP_CONTENT : (int) mIconHeight);
|
||||
if (mIconGravity == Gravity.LEFT) {
|
||||
lp.rightMargin = (int) mIconMargin;
|
||||
} else if (mIconGravity == Gravity.RIGHT) {
|
||||
lp.leftMargin = (int) mIconMargin;
|
||||
} else if (mIconGravity == Gravity.BOTTOM) {
|
||||
lp.topMargin = (int) mIconMargin;
|
||||
} else {
|
||||
lp.bottomMargin = (int) mIconMargin;
|
||||
}
|
||||
|
||||
iv_tab_icon.setLayoutParams(lp);
|
||||
} else {
|
||||
iv_tab_icon.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTabSelection(int position) {
|
||||
for (int i = 0; i < mTabCount; ++i) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
final boolean isSelect = i == position;
|
||||
TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor);
|
||||
ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);
|
||||
CustomTabEntity tabEntity = mTabEntitys.get(i);
|
||||
iv_tab_icon.setImageResource(isSelect ? tabEntity.getTabSelectedIcon() : tabEntity.getTabUnselectedIcon());
|
||||
if (mTextBold == TEXT_BOLD_WHEN_SELECT) {
|
||||
tab_title.getPaint().setFakeBoldText(isSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calcOffset() {
|
||||
final View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
mCurrentP.left = currentTabView.getLeft();
|
||||
mCurrentP.right = currentTabView.getRight();
|
||||
|
||||
final View lastTabView = mTabsContainer.getChildAt(this.mLastTab);
|
||||
mLastP.left = lastTabView.getLeft();
|
||||
mLastP.right = lastTabView.getRight();
|
||||
|
||||
// Log.d("AAA", "mLastP--->" + mLastP.left + "&" + mLastP.right);
|
||||
// Log.d("AAA", "mCurrentP--->" + mCurrentP.left + "&" + mCurrentP.right);
|
||||
if (mLastP.left == mCurrentP.left && mLastP.right == mCurrentP.right) {
|
||||
invalidate();
|
||||
} else {
|
||||
mValueAnimator.setObjectValues(mLastP, mCurrentP);
|
||||
if (mIndicatorBounceEnable) {
|
||||
mValueAnimator.setInterpolator(mInterpolator);
|
||||
}
|
||||
|
||||
if (mIndicatorAnimDuration < 0) {
|
||||
mIndicatorAnimDuration = mIndicatorBounceEnable ? 500 : 250;
|
||||
}
|
||||
mValueAnimator.setDuration(mIndicatorAnimDuration);
|
||||
mValueAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void calcIndicatorRect() {
|
||||
View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
float left = currentTabView.getLeft();
|
||||
float right = currentTabView.getRight();
|
||||
|
||||
mIndicatorRect.left = (int) left;
|
||||
mIndicatorRect.right = (int) right;
|
||||
|
||||
if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip
|
||||
|
||||
} else {//indicatorWidth大于0时,圆角矩形以及三角形
|
||||
float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2;
|
||||
|
||||
mIndicatorRect.left = (int) indicatorLeft;
|
||||
mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue();
|
||||
mIndicatorRect.left = (int) p.left;
|
||||
mIndicatorRect.right = (int) p.right;
|
||||
|
||||
if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip
|
||||
|
||||
} else {//indicatorWidth大于0时,圆角矩形以及三角形
|
||||
float indicatorLeft = p.left + (currentTabView.getWidth() - mIndicatorWidth) / 2;
|
||||
|
||||
mIndicatorRect.left = (int) indicatorLeft;
|
||||
mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth);
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private boolean mIsFirstDraw = true;
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (isInEditMode() || mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int height = getHeight();
|
||||
int paddingLeft = getPaddingLeft();
|
||||
// draw divider
|
||||
if (mDividerWidth > 0) {
|
||||
mDividerPaint.setStrokeWidth(mDividerWidth);
|
||||
mDividerPaint.setColor(mDividerColor);
|
||||
for (int i = 0; i < mTabCount - 1; i++) {
|
||||
View tab = mTabsContainer.getChildAt(i);
|
||||
canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
// draw underline
|
||||
if (mUnderlineHeight > 0) {
|
||||
mRectPaint.setColor(mUnderlineColor);
|
||||
if (mUnderlineGravity == Gravity.BOTTOM) {
|
||||
canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint);
|
||||
} else {
|
||||
canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint);
|
||||
}
|
||||
}
|
||||
|
||||
//draw indicator line
|
||||
if (mIndicatorAnimEnable) {
|
||||
if (mIsFirstDraw) {
|
||||
mIsFirstDraw = false;
|
||||
calcIndicatorRect();
|
||||
}
|
||||
} else {
|
||||
calcIndicatorRect();
|
||||
}
|
||||
|
||||
|
||||
if (mIndicatorStyle == STYLE_TRIANGLE) {
|
||||
if (mIndicatorHeight > 0) {
|
||||
mTrianglePaint.setColor(mIndicatorColor);
|
||||
mTrianglePath.reset();
|
||||
mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height);
|
||||
mTrianglePath.close();
|
||||
canvas.drawPath(mTrianglePath, mTrianglePaint);
|
||||
}
|
||||
} else if (mIndicatorStyle == STYLE_BLOCK) {
|
||||
if (mIndicatorHeight < 0) {
|
||||
mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) {
|
||||
mIndicatorCornerRadius = mIndicatorHeight / 2;
|
||||
}
|
||||
|
||||
mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight),
|
||||
(int) (mIndicatorMarginTop + mIndicatorHeight));
|
||||
mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
}
|
||||
} else {
|
||||
/* mRectPaint.setColor(mIndicatorColor);
|
||||
calcIndicatorRect();
|
||||
canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight,
|
||||
mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
if (mIndicatorGravity == Gravity.BOTTOM) {
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
height - (int) mIndicatorMarginBottom);
|
||||
} else {
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
(int) mIndicatorHeight + (int) mIndicatorMarginTop);
|
||||
}
|
||||
mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
public void setCurrentTab(int currentTab) {
|
||||
mLastTab = this.mCurrentTab;
|
||||
this.mCurrentTab = currentTab;
|
||||
updateTabSelection(currentTab);
|
||||
if (mFragmentChangeManager != null) {
|
||||
mFragmentChangeManager.setFragments(currentTab);
|
||||
}
|
||||
if (mIndicatorAnimEnable) {
|
||||
calcOffset();
|
||||
} else {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIndicatorStyle(int indicatorStyle) {
|
||||
this.mIndicatorStyle = indicatorStyle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTabPadding(float tabPadding) {
|
||||
this.mTabPadding = dp2px(tabPadding);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabSpaceEqual(boolean tabSpaceEqual) {
|
||||
this.mTabSpaceEqual = tabSpaceEqual;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabWidth(float tabWidth) {
|
||||
this.mTabWidth = dp2px(tabWidth);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int indicatorColor) {
|
||||
this.mIndicatorColor = indicatorColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorHeight(float indicatorHeight) {
|
||||
this.mIndicatorHeight = dp2px(indicatorHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidth(float indicatorWidth) {
|
||||
this.mIndicatorWidth = dp2px(indicatorWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorCornerRadius(float indicatorCornerRadius) {
|
||||
this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorGravity(int indicatorGravity) {
|
||||
this.mIndicatorGravity = indicatorGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop,
|
||||
float indicatorMarginRight, float indicatorMarginBottom) {
|
||||
this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft);
|
||||
this.mIndicatorMarginTop = dp2px(indicatorMarginTop);
|
||||
this.mIndicatorMarginRight = dp2px(indicatorMarginRight);
|
||||
this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorAnimDuration(long indicatorAnimDuration) {
|
||||
this.mIndicatorAnimDuration = indicatorAnimDuration;
|
||||
}
|
||||
|
||||
public void setIndicatorAnimEnable(boolean indicatorAnimEnable) {
|
||||
this.mIndicatorAnimEnable = indicatorAnimEnable;
|
||||
}
|
||||
|
||||
public void setIndicatorBounceEnable(boolean indicatorBounceEnable) {
|
||||
this.mIndicatorBounceEnable = indicatorBounceEnable;
|
||||
}
|
||||
|
||||
public void setUnderlineColor(int underlineColor) {
|
||||
this.mUnderlineColor = underlineColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineHeight(float underlineHeight) {
|
||||
this.mUnderlineHeight = dp2px(underlineHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineGravity(int underlineGravity) {
|
||||
this.mUnderlineGravity = underlineGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerColor(int dividerColor) {
|
||||
this.mDividerColor = dividerColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerWidth(float dividerWidth) {
|
||||
this.mDividerWidth = dp2px(dividerWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerPadding(float dividerPadding) {
|
||||
this.mDividerPadding = dp2px(dividerPadding);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTextsize(float textsize) {
|
||||
this.mTextsize = sp2px(textsize);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextSelectColor(int textSelectColor) {
|
||||
this.mTextSelectColor = textSelectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextUnselectColor(int textUnselectColor) {
|
||||
this.mTextUnselectColor = textUnselectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextBold(int textBold) {
|
||||
this.mTextBold = textBold;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIconVisible(boolean iconVisible) {
|
||||
this.mIconVisible = iconVisible;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIconGravity(int iconGravity) {
|
||||
this.mIconGravity = iconGravity;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setIconWidth(float iconWidth) {
|
||||
this.mIconWidth = dp2px(iconWidth);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIconHeight(float iconHeight) {
|
||||
this.mIconHeight = dp2px(iconHeight);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIconMargin(float iconMargin) {
|
||||
this.mIconMargin = dp2px(iconMargin);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextAllCaps(boolean textAllCaps) {
|
||||
this.mTextAllCaps = textAllCaps;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
|
||||
public int getTabCount() {
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
public int getCurrentTab() {
|
||||
return mCurrentTab;
|
||||
}
|
||||
|
||||
public int getIndicatorStyle() {
|
||||
return mIndicatorStyle;
|
||||
}
|
||||
|
||||
public float getTabPadding() {
|
||||
return mTabPadding;
|
||||
}
|
||||
|
||||
public boolean isTabSpaceEqual() {
|
||||
return mTabSpaceEqual;
|
||||
}
|
||||
|
||||
public float getTabWidth() {
|
||||
return mTabWidth;
|
||||
}
|
||||
|
||||
public int getIndicatorColor() {
|
||||
return mIndicatorColor;
|
||||
}
|
||||
|
||||
public float getIndicatorHeight() {
|
||||
return mIndicatorHeight;
|
||||
}
|
||||
|
||||
public float getIndicatorWidth() {
|
||||
return mIndicatorWidth;
|
||||
}
|
||||
|
||||
public float getIndicatorCornerRadius() {
|
||||
return mIndicatorCornerRadius;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginLeft() {
|
||||
return mIndicatorMarginLeft;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginTop() {
|
||||
return mIndicatorMarginTop;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginRight() {
|
||||
return mIndicatorMarginRight;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginBottom() {
|
||||
return mIndicatorMarginBottom;
|
||||
}
|
||||
|
||||
public long getIndicatorAnimDuration() {
|
||||
return mIndicatorAnimDuration;
|
||||
}
|
||||
|
||||
public boolean isIndicatorAnimEnable() {
|
||||
return mIndicatorAnimEnable;
|
||||
}
|
||||
|
||||
public boolean isIndicatorBounceEnable() {
|
||||
return mIndicatorBounceEnable;
|
||||
}
|
||||
|
||||
public int getUnderlineColor() {
|
||||
return mUnderlineColor;
|
||||
}
|
||||
|
||||
public float getUnderlineHeight() {
|
||||
return mUnderlineHeight;
|
||||
}
|
||||
|
||||
public int getDividerColor() {
|
||||
return mDividerColor;
|
||||
}
|
||||
|
||||
public float getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
public float getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
public float getTextsize() {
|
||||
return mTextsize;
|
||||
}
|
||||
|
||||
public int getTextSelectColor() {
|
||||
return mTextSelectColor;
|
||||
}
|
||||
|
||||
public int getTextUnselectColor() {
|
||||
return mTextUnselectColor;
|
||||
}
|
||||
|
||||
public int getTextBold() {
|
||||
return mTextBold;
|
||||
}
|
||||
|
||||
public boolean isTextAllCaps() {
|
||||
return mTextAllCaps;
|
||||
}
|
||||
|
||||
public int getIconGravity() {
|
||||
return mIconGravity;
|
||||
}
|
||||
|
||||
public float getIconWidth() {
|
||||
return mIconWidth;
|
||||
}
|
||||
|
||||
public float getIconHeight() {
|
||||
return mIconHeight;
|
||||
}
|
||||
|
||||
public float getIconMargin() {
|
||||
return mIconMargin;
|
||||
}
|
||||
|
||||
public boolean isIconVisible() {
|
||||
return mIconVisible;
|
||||
}
|
||||
|
||||
|
||||
public ImageView getIconView(int tab) {
|
||||
View tabView = mTabsContainer.getChildAt(tab);
|
||||
ImageView iv_tab_icon = (ImageView) tabView.findViewById(R.id.iv_tab_icon);
|
||||
return iv_tab_icon;
|
||||
}
|
||||
|
||||
public TextView getTitleView(int tab) {
|
||||
View tabView = mTabsContainer.getChildAt(tab);
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
return tv_tab_title;
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
|
||||
// show MsgTipView
|
||||
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private SparseArray<Boolean> mInitSetMap = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* 显示未读消息
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
* @param num num小于等于0显示红点,num大于0显示数字
|
||||
*/
|
||||
public void showMsg(int position, int num) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
UnreadMsgUtils.show(tipView, num);
|
||||
|
||||
if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mIconVisible) {
|
||||
setMsgMargin(position, 2, 2);
|
||||
} else {
|
||||
setMsgMargin(position, 0,
|
||||
mIconGravity == Gravity.LEFT || mIconGravity == Gravity.RIGHT ? 4 : 0);
|
||||
}
|
||||
|
||||
mInitSetMap.put(position, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示未读红点
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
*/
|
||||
public void showDot(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
showMsg(position, 0);
|
||||
}
|
||||
|
||||
public void hideMsg(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
tipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle(int tab) {
|
||||
return mTabEntitys.get(tab).getTabTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置提示红点偏移,注意
|
||||
* 1.控件为固定高度:参照点为tab内容的右上角
|
||||
* 2.控件高度不固定(WRAP_CONTENT):参照点为tab内容的右上角,此时高度已是红点的最高显示范围,所以这时bottomPadding其实就是topPadding
|
||||
*/
|
||||
public void setMsgMargin(int position, float leftPadding, float bottomPadding) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString());
|
||||
float textHeight = mTextPaint.descent() - mTextPaint.ascent();
|
||||
MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams();
|
||||
|
||||
float iconH = mIconHeight;
|
||||
float margin = 0;
|
||||
if (mIconVisible) {
|
||||
if (iconH <= 0) {
|
||||
iconH = mContext.getResources().getDrawable(mTabEntitys.get(position).getTabSelectedIcon()).getIntrinsicHeight();
|
||||
}
|
||||
margin = mIconMargin;
|
||||
}
|
||||
|
||||
if (mIconGravity == Gravity.TOP || mIconGravity == Gravity.BOTTOM) {
|
||||
lp.leftMargin = dp2px(leftPadding);
|
||||
lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight - iconH - margin) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding);
|
||||
} else {
|
||||
lp.leftMargin = dp2px(leftPadding);
|
||||
lp.topMargin = mHeight > 0 ? (int) (mHeight - Math.max(textHeight, iconH)) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding);
|
||||
}
|
||||
|
||||
tipView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 */
|
||||
public MsgView getMsgView(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
return tipView;
|
||||
}
|
||||
|
||||
private OnTabSelectListener mListener;
|
||||
|
||||
public void setOnTabSelectListener(OnTabSelectListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("instanceState", super.onSaveInstanceState());
|
||||
bundle.putInt("mCurrentTab", mCurrentTab);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
mCurrentTab = bundle.getInt("mCurrentTab");
|
||||
state = bundle.getParcelable("instanceState");
|
||||
if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) {
|
||||
updateTabSelection(mCurrentTab);
|
||||
}
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
|
||||
class IndicatorPoint {
|
||||
public float left;
|
||||
public float right;
|
||||
}
|
||||
|
||||
private IndicatorPoint mCurrentP = new IndicatorPoint();
|
||||
private IndicatorPoint mLastP = new IndicatorPoint();
|
||||
|
||||
class PointEvaluator implements TypeEvaluator<IndicatorPoint> {
|
||||
@Override
|
||||
public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) {
|
||||
float left = startValue.left + fraction * (endValue.left - startValue.left);
|
||||
float right = startValue.right + fraction * (endValue.right - startValue.right);
|
||||
IndicatorPoint point = new IndicatorPoint();
|
||||
point.left = left;
|
||||
point.right = right;
|
||||
return point;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected int dp2px(float dp) {
|
||||
final float scale = mContext.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
protected int sp2px(float sp) {
|
||||
final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (sp * scale + 0.5f);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,964 @@
|
||||
package com.example.moduletablayout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
|
||||
import com.example.moduletablayout.listener.OnTabSelectListener;
|
||||
import com.example.moduletablayout.utils.UnreadMsgUtils;
|
||||
import com.example.moduletablayout.widget.MsgView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* ProjectName: isolated-island
|
||||
* Package: com.flyco.tablayout
|
||||
* Description: 带图片的SlidingTabLayout
|
||||
* Author: 姚闻达
|
||||
* CreateDate: 2020/11/12 17:18
|
||||
* UpdateUser: 更新者
|
||||
* UpdateDate: 2020/11/12 17:18
|
||||
* UpdateRemark: 更新说明
|
||||
* Version: 1.0
|
||||
*/
|
||||
public class CustomImgSlidingTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener {
|
||||
|
||||
private Context mContext;
|
||||
private ViewPager mViewPager;
|
||||
private ArrayList<Integer> mSelectedTitles;
|
||||
private ArrayList<Integer> mUnSelectedTitles;
|
||||
private LinearLayout mTabsContainer;
|
||||
private int mCurrentTab;
|
||||
private float mCurrentPositionOffset;
|
||||
private int mTabCount;
|
||||
/**
|
||||
* 用于绘制显示器
|
||||
*/
|
||||
private Rect mIndicatorRect = new Rect();
|
||||
/**
|
||||
* 用于实现滚动居中
|
||||
*/
|
||||
private Rect mTabRect = new Rect();
|
||||
// private GradientDrawable mIndicatorDrawable = new GradientDrawable();
|
||||
private GradientDrawable mIndicatorDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[]{Color.parseColor("#FFBB53FF"), Color.parseColor("#FF514FFF")});
|
||||
private BitmapDrawable bitmapDrawable = new BitmapDrawable();
|
||||
|
||||
|
||||
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Path mTrianglePath = new Path();
|
||||
private static final int STYLE_NORMAL = 0;
|
||||
private static final int STYLE_TRIANGLE = 1;
|
||||
private static final int STYLE_BLOCK = 2;
|
||||
private int mIndicatorStyle = STYLE_NORMAL;
|
||||
|
||||
private float mTabPadding;
|
||||
private boolean mTabSpaceEqual;
|
||||
private float mTabWidth;
|
||||
|
||||
/**
|
||||
* indicator
|
||||
*/
|
||||
private int mIndicatorColor;
|
||||
private float mIndicatorHeight;
|
||||
private float mIndicatorWidth;
|
||||
private float mIndicatorCornerRadius;
|
||||
private float mIndicatorMarginLeft;
|
||||
private float mIndicatorMarginTop;
|
||||
private float mIndicatorMarginRight;
|
||||
private float mIndicatorMarginBottom;
|
||||
private int mIndicatorGravity;
|
||||
private boolean mIndicatorWidthEqualTitle;
|
||||
|
||||
/**
|
||||
* underline
|
||||
*/
|
||||
private int mUnderlineColor;
|
||||
private float mUnderlineHeight;
|
||||
private int mUnderlineGravity;
|
||||
|
||||
/**
|
||||
* divider
|
||||
*/
|
||||
private int mDividerColor;
|
||||
private float mDividerWidth;
|
||||
private float mDividerPadding;
|
||||
|
||||
/**
|
||||
* title
|
||||
*/
|
||||
private int mTextSelectColor;
|
||||
private int mTextUnselectColor;
|
||||
|
||||
private int mLastScrollX;
|
||||
private int mHeight;
|
||||
private boolean mSnapOnTabClick;
|
||||
private boolean showCateIndicator;
|
||||
private Bitmap mBitmap;
|
||||
private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public CustomImgSlidingTabLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public CustomImgSlidingTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomImgSlidingTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.flyco_ic_indicator_selected_category);
|
||||
setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口
|
||||
setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
|
||||
this.mContext = context;
|
||||
mTabsContainer = new LinearLayout(context);
|
||||
addView(mTabsContainer);
|
||||
|
||||
obtainAttributes(context, attrs);
|
||||
if (showCateIndicator) {
|
||||
mIndicatorDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[]{Color.parseColor("#FF6FD0FF"), Color.TRANSPARENT});
|
||||
}
|
||||
bitmapDrawable.setAntiAlias(true);
|
||||
|
||||
//get layout_height
|
||||
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
|
||||
|
||||
if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) {
|
||||
} else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) {
|
||||
} else {
|
||||
int[] systemAttrs = {android.R.attr.layout_height};
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
|
||||
mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void obtainAttributes(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CustomImgSlidingTabLayout);
|
||||
|
||||
mIndicatorStyle = ta.getInt(R.styleable.CustomImgSlidingTabLayout_tl_indicator_style, STYLE_NORMAL);
|
||||
mIndicatorColor = ta.getColor(R.styleable.CustomImgSlidingTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff"));
|
||||
mIndicatorHeight = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_height,
|
||||
dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2)));
|
||||
mIndicatorWidth = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1));
|
||||
mIndicatorCornerRadius = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0));
|
||||
mIndicatorMarginLeft = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_margin_left, dp2px(0));
|
||||
mIndicatorMarginTop = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorMarginRight = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_margin_right, dp2px(0));
|
||||
mIndicatorMarginBottom = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorGravity = ta.getInt(R.styleable.CustomImgSlidingTabLayout_tl_indicator_gravity, Gravity.BOTTOM);
|
||||
mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.CustomImgSlidingTabLayout_tl_indicator_width_equal_title, false);
|
||||
|
||||
mUnderlineColor = ta.getColor(R.styleable.CustomImgSlidingTabLayout_tl_underline_color, Color.parseColor("#ffffff"));
|
||||
mUnderlineHeight = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_underline_height, dp2px(0));
|
||||
mUnderlineGravity = ta.getInt(R.styleable.CustomImgSlidingTabLayout_tl_underline_gravity, Gravity.BOTTOM);
|
||||
|
||||
mDividerColor = ta.getColor(R.styleable.CustomImgSlidingTabLayout_tl_divider_color, Color.parseColor("#ffffff"));
|
||||
mDividerWidth = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_divider_width, dp2px(0));
|
||||
mDividerPadding = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_divider_padding, dp2px(12));
|
||||
|
||||
mTextSelectColor = ta.getColor(R.styleable.CustomImgSlidingTabLayout_tl_textSelectColor, Color.parseColor("#ffffff"));
|
||||
mTextUnselectColor = ta.getColor(R.styleable.CustomImgSlidingTabLayout_tl_textUnselectColor, Color.parseColor("#AAffffff"));
|
||||
|
||||
mTabSpaceEqual = ta.getBoolean(R.styleable.CustomImgSlidingTabLayout_tl_tab_space_equal, false);
|
||||
mTabWidth = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_tab_width, dp2px(-1));
|
||||
mTabPadding = ta.getDimension(R.styleable.CustomImgSlidingTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20));
|
||||
showCateIndicator = ta.getBoolean(R.styleable.CustomImgSlidingTabLayout_tl_imgShowCateIndicator, false);
|
||||
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联ViewPager
|
||||
*/
|
||||
public void setViewPager(ViewPager vp) {
|
||||
if (vp == null || vp.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager or ViewPager rightAdapter can not be NULL !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况
|
||||
*/
|
||||
public void setViewPager(ViewPager vp, Integer[] selectedTitles,Integer[] unselectedTitles) {
|
||||
if (vp == null || vp.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager or ViewPager rightAdapter can not be NULL !");
|
||||
}
|
||||
|
||||
if (selectedTitles == null || selectedTitles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be EMPTY !");
|
||||
}
|
||||
|
||||
if (selectedTitles.length != vp.getAdapter().getCount()) {
|
||||
throw new IllegalStateException("Titles length must be the same as the page count !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
mSelectedTitles = new ArrayList<>();
|
||||
mUnSelectedTitles = new ArrayList<>();
|
||||
Collections.addAll(mSelectedTitles, selectedTitles);
|
||||
Collections.addAll(mUnSelectedTitles, unselectedTitles);
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联ViewPager,用于连适配器都不想自己实例化的情况
|
||||
*/
|
||||
public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList<Fragment> fragments) {
|
||||
if (vp == null) {
|
||||
throw new IllegalStateException("ViewPager can not be NULL !");
|
||||
}
|
||||
|
||||
if (titles == null || titles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be EMPTY !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles));
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据
|
||||
*/
|
||||
public void notifyDataSetChanged() {
|
||||
mTabsContainer.removeAllViews();
|
||||
this.mTabCount = mSelectedTitles == null ? mViewPager.getAdapter().getCount() : mSelectedTitles.size();
|
||||
View tabView;
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
tabView = View.inflate(mContext, R.layout.flyco_layout_tab_img, null);
|
||||
int pageTitle = mSelectedTitles.get(i);
|
||||
addTab(i, pageTitle, tabView);
|
||||
}
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void addNewTab(int titleImg) {
|
||||
View tabView = View.inflate(mContext, R.layout.flyco_layout_tab_img, null);
|
||||
if (mSelectedTitles != null) {
|
||||
mSelectedTitles.add(titleImg);
|
||||
}
|
||||
|
||||
int pageTitle = mSelectedTitles.get(mTabCount);
|
||||
addTab(mTabCount, pageTitle, tabView);
|
||||
this.mTabCount = mSelectedTitles == null ? mViewPager.getAdapter().getCount() : mSelectedTitles.size();
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并添加tab
|
||||
*/
|
||||
private void addTab(final int position, int titleImg, View tabView) {
|
||||
ImageView iv_tab_title = (ImageView) tabView.findViewById(R.id.iv_tab_title);
|
||||
if (iv_tab_title != null) {
|
||||
if (titleImg != 0) iv_tab_title.setImageResource(titleImg);
|
||||
}
|
||||
|
||||
tabView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = mTabsContainer.indexOfChild(v);
|
||||
if (position != -1) {
|
||||
if (mViewPager.getCurrentItem() != position) {
|
||||
if (mSnapOnTabClick) {
|
||||
mViewPager.setCurrentItem(position, false);
|
||||
} else {
|
||||
mViewPager.setCurrentItem(position);
|
||||
}
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onTabSelect(position);
|
||||
}
|
||||
} else {
|
||||
if (mListener != null) {
|
||||
mListener.onTabReselect(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** 每一个Tab的布局参数 */
|
||||
LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?
|
||||
new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
|
||||
new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
if (mTabWidth > 0) {
|
||||
lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
|
||||
mTabsContainer.addView(tabView, position, lp_tab);
|
||||
}
|
||||
|
||||
private void updateTabStyles() {
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
View v = mTabsContainer.getChildAt(i);
|
||||
// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom());
|
||||
ImageView iv_tab_title = (ImageView) v.findViewById(R.id.iv_tab_title);
|
||||
if (iv_tab_title != null) {
|
||||
if(mUnSelectedTitles != null && mUnSelectedTitles.size() > 0) {
|
||||
iv_tab_title.setImageResource(i == mCurrentTab ? mSelectedTitles.get(i) : mUnSelectedTitles.get(i));
|
||||
}else {
|
||||
iv_tab_title.setImageResource(mSelectedTitles.get(i));
|
||||
}
|
||||
iv_tab_title.setPadding((int) mTabPadding, 5, (int) mTabPadding, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
/**
|
||||
* position:当前View的位置
|
||||
* mCurrentPositionOffset:当前View的偏移量比例.[0,1)
|
||||
*/
|
||||
this.mCurrentTab = position;
|
||||
this.mCurrentPositionOffset = positionOffset;
|
||||
scrollToCurrentTab();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
updateTabSelection(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* HorizontalScrollView滚到当前tab,并且居中显示
|
||||
*/
|
||||
private void scrollToCurrentTab() {
|
||||
if (mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth());
|
||||
/**当前Tab的left+当前Tab的Width乘以positionOffset*/
|
||||
int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset;
|
||||
|
||||
if (mCurrentTab > 0 || offset > 0) {
|
||||
/**HorizontalScrollView移动到当前tab,并居中*/
|
||||
newScrollX -= getWidth() / 2 - getPaddingLeft();
|
||||
calcIndicatorRect();
|
||||
newScrollX += ((mTabRect.right - mTabRect.left) / 2);
|
||||
}
|
||||
|
||||
if (newScrollX != mLastScrollX) {
|
||||
mLastScrollX = newScrollX;
|
||||
/** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量
|
||||
* x:表示离起始位置的x水平方向的偏移量
|
||||
* y:表示离起始位置的y垂直方向的偏移量
|
||||
*/
|
||||
scrollTo(newScrollX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTabSelection(int position) {
|
||||
for (int i = 0; i < mTabCount; ++i) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
final boolean isSelect = i == position;
|
||||
ImageView tab_title = tabView.findViewById(R.id.iv_tab_title);
|
||||
|
||||
if (tab_title != null) {
|
||||
if(mUnSelectedTitles != null && mUnSelectedTitles.size() > 0) {
|
||||
tab_title.setImageResource(isSelect ? mSelectedTitles.get(i) : mUnSelectedTitles.get(i));
|
||||
} else {
|
||||
tab_title.setImageResource(mSelectedTitles.get(i));
|
||||
}
|
||||
// ViewCompat.animate(tab_title).setDuration(200).scaleX(isSelect ? 1.3f : 1f).scaleY(isSelect ? 1.3f : 1f).alpha(isSelect ? 1f : 0.4f).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float margin;
|
||||
|
||||
private void calcIndicatorRect() {
|
||||
View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
float left = currentTabView.getLeft();
|
||||
float right = currentTabView.getRight();
|
||||
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
ImageView tab_title = (ImageView) currentTabView.findViewById(R.id.iv_tab_title);
|
||||
// float textWidth = mTextPaint.measureText(tab_title.getText().toString());
|
||||
// float imgWidth = calcImgWidth(tab_title.get)
|
||||
float imgWidth = tab_title.getMeasuredWidth();
|
||||
margin = (right - left - imgWidth) / 2;
|
||||
}
|
||||
|
||||
if (this.mCurrentTab < mTabCount - 1) {
|
||||
View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1);
|
||||
float nextTabLeft = nextTabView.getLeft();
|
||||
float nextTabRight = nextTabView.getRight();
|
||||
|
||||
left = left + mCurrentPositionOffset * (nextTabLeft - left);
|
||||
right = right + mCurrentPositionOffset * (nextTabRight - right);
|
||||
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
ImageView next_tab_title = (ImageView) nextTabView.findViewById(R.id.iv_tab_title);
|
||||
// float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString());
|
||||
float nextImgWidth = next_tab_title.getMeasuredWidth();
|
||||
float nextMargin = (nextTabRight - nextTabLeft - nextImgWidth) / 2;
|
||||
margin = margin + mCurrentPositionOffset * (nextMargin - margin);
|
||||
}
|
||||
}
|
||||
|
||||
mIndicatorRect.left = (int) left;
|
||||
mIndicatorRect.right = (int) right;
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
mIndicatorRect.left = (int) (left + margin - 1);
|
||||
mIndicatorRect.right = (int) (right - margin - 1);
|
||||
}
|
||||
|
||||
mTabRect.left = (int) left;
|
||||
mTabRect.right = (int) right;
|
||||
|
||||
if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip
|
||||
|
||||
} else {//indicatorWidth大于0时,圆角矩形以及三角形
|
||||
float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2;
|
||||
|
||||
if (this.mCurrentTab < mTabCount - 1) {
|
||||
View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1);
|
||||
indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2);
|
||||
}
|
||||
|
||||
mIndicatorRect.left = (int) indicatorLeft;
|
||||
mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth);
|
||||
}
|
||||
}
|
||||
|
||||
private float calcImgWidth(int resId) {
|
||||
BitmapFactory.Options opts = new BitmapFactory.Options();
|
||||
opts.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeResource(getContext().getResources(),resId,opts);
|
||||
return opts.outWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (isInEditMode() || mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int height = getHeight();
|
||||
int paddingLeft = getPaddingLeft();
|
||||
// draw divider
|
||||
if (mDividerWidth > 0) {
|
||||
mDividerPaint.setStrokeWidth(mDividerWidth);
|
||||
mDividerPaint.setColor(mDividerColor);
|
||||
for (int i = 0; i < mTabCount - 1; i++) {
|
||||
View tab = mTabsContainer.getChildAt(i);
|
||||
canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
// draw underline
|
||||
if (mUnderlineHeight > 0) {
|
||||
mRectPaint.setColor(mUnderlineColor);
|
||||
if (mUnderlineGravity == Gravity.BOTTOM) {
|
||||
canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint);
|
||||
} else {
|
||||
canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint);
|
||||
}
|
||||
}
|
||||
|
||||
//draw indicator line
|
||||
|
||||
calcIndicatorRect();
|
||||
if (mIndicatorStyle == STYLE_TRIANGLE) {
|
||||
if (mIndicatorHeight > 0) {
|
||||
mTrianglePaint.setColor(mIndicatorColor);
|
||||
mTrianglePath.reset();
|
||||
mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height);
|
||||
mTrianglePath.close();
|
||||
canvas.drawPath(mTrianglePath, mTrianglePaint);
|
||||
}
|
||||
} else if (mIndicatorStyle == STYLE_BLOCK) {
|
||||
if (mIndicatorHeight < 0) {
|
||||
mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) {
|
||||
mIndicatorCornerRadius = mIndicatorHeight / 2;
|
||||
}
|
||||
|
||||
// mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
// (int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight),
|
||||
// (int) (mIndicatorMarginTop + mIndicatorHeight));
|
||||
// mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
// mIndicatorDrawable.draw(canvas);
|
||||
bitmapDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight),
|
||||
(int) (mIndicatorMarginTop + mIndicatorHeight));
|
||||
bitmapDrawable.draw(canvas);
|
||||
}
|
||||
} else {
|
||||
if (mIndicatorHeight > 0) {
|
||||
if (mIndicatorGravity == Gravity.BOTTOM) {
|
||||
// mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
// height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom,
|
||||
// paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
// height - (int) mIndicatorMarginBottom);
|
||||
bitmapDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
height - (int) mIndicatorMarginBottom);
|
||||
} else {
|
||||
// mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
// (int) mIndicatorMarginTop,
|
||||
// paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
// (int) mIndicatorHeight + (int) mIndicatorMarginTop);
|
||||
bitmapDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
(int) mIndicatorHeight + (int) mIndicatorMarginTop);
|
||||
}
|
||||
// mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
if (showCateIndicator) {
|
||||
canvas.drawBitmap(mBitmap, mIndicatorRect.left + mIndicatorMarginLeft
|
||||
, mIndicatorMarginTop, mBitmapPaint);
|
||||
} else {
|
||||
// mIndicatorDrawable.draw(canvas);
|
||||
bitmapDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
public void setCurrentTab(int currentTab) {
|
||||
if (mCurrentTab == currentTab) {
|
||||
updateTabSelection(currentTab);
|
||||
}
|
||||
this.mCurrentTab = currentTab;
|
||||
mViewPager.setCurrentItem(currentTab);
|
||||
|
||||
}
|
||||
|
||||
public void setCurrentTab(int currentTab, boolean smoothScroll) {
|
||||
this.mCurrentTab = currentTab;
|
||||
mViewPager.setCurrentItem(currentTab, smoothScroll);
|
||||
}
|
||||
|
||||
public void setIndicatorStyle(int indicatorStyle) {
|
||||
this.mIndicatorStyle = indicatorStyle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTabPadding(float tabPadding) {
|
||||
this.mTabPadding = dp2px(tabPadding);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabSpaceEqual(boolean tabSpaceEqual) {
|
||||
this.mTabSpaceEqual = tabSpaceEqual;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabWidth(float tabWidth) {
|
||||
this.mTabWidth = dp2px(tabWidth);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int indicatorColor) {
|
||||
this.mIndicatorColor = indicatorColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorHeight(float indicatorHeight) {
|
||||
this.mIndicatorHeight = dp2px(indicatorHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidth(float indicatorWidth) {
|
||||
this.mIndicatorWidth = dp2px(indicatorWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorCornerRadius(float indicatorCornerRadius) {
|
||||
this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorGravity(int indicatorGravity) {
|
||||
this.mIndicatorGravity = indicatorGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop,
|
||||
float indicatorMarginRight, float indicatorMarginBottom) {
|
||||
this.mIndicatorMarginLeft = indicatorMarginLeft;
|
||||
this.mIndicatorMarginTop = indicatorMarginTop;
|
||||
this.mIndicatorMarginRight = indicatorMarginRight;
|
||||
this.mIndicatorMarginBottom = indicatorMarginBottom;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) {
|
||||
this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineColor(int underlineColor) {
|
||||
this.mUnderlineColor = underlineColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineHeight(float underlineHeight) {
|
||||
this.mUnderlineHeight = dp2px(underlineHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineGravity(int underlineGravity) {
|
||||
this.mUnderlineGravity = underlineGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerColor(int dividerColor) {
|
||||
this.mDividerColor = dividerColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerWidth(float dividerWidth) {
|
||||
this.mDividerWidth = dp2px(dividerWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerPadding(float dividerPadding) {
|
||||
this.mDividerPadding = dp2px(dividerPadding);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTextSelectColor(int textSelectColor) {
|
||||
this.mTextSelectColor = textSelectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextUnselectColor(int textUnselectColor) {
|
||||
this.mTextUnselectColor = textUnselectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setSnapOnTabClick(boolean snapOnTabClick) {
|
||||
mSnapOnTabClick = snapOnTabClick;
|
||||
}
|
||||
|
||||
public int getTabCount() {
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
public int getCurrentTab() {
|
||||
return mCurrentTab;
|
||||
}
|
||||
|
||||
public int getIndicatorStyle() {
|
||||
return mIndicatorStyle;
|
||||
}
|
||||
|
||||
public float getTabPadding() {
|
||||
return mTabPadding;
|
||||
}
|
||||
|
||||
public boolean isTabSpaceEqual() {
|
||||
return mTabSpaceEqual;
|
||||
}
|
||||
|
||||
public float getTabWidth() {
|
||||
return mTabWidth;
|
||||
}
|
||||
|
||||
public int getIndicatorColor() {
|
||||
return mIndicatorColor;
|
||||
}
|
||||
|
||||
public float getIndicatorHeight() {
|
||||
return mIndicatorHeight;
|
||||
}
|
||||
|
||||
public float getIndicatorWidth() {
|
||||
return mIndicatorWidth;
|
||||
}
|
||||
|
||||
public float getIndicatorCornerRadius() {
|
||||
return mIndicatorCornerRadius;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginLeft() {
|
||||
return mIndicatorMarginLeft;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginTop() {
|
||||
return mIndicatorMarginTop;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginRight() {
|
||||
return mIndicatorMarginRight;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginBottom() {
|
||||
return mIndicatorMarginBottom;
|
||||
}
|
||||
|
||||
public int getUnderlineColor() {
|
||||
return mUnderlineColor;
|
||||
}
|
||||
|
||||
public float getUnderlineHeight() {
|
||||
return mUnderlineHeight;
|
||||
}
|
||||
|
||||
public int getDividerColor() {
|
||||
return mDividerColor;
|
||||
}
|
||||
|
||||
public float getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
public float getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
public int getTextSelectColor() {
|
||||
return mTextSelectColor;
|
||||
}
|
||||
|
||||
public int getTextUnselectColor() {
|
||||
return mTextUnselectColor;
|
||||
}
|
||||
|
||||
public void setBitmapDrawable(int resId){
|
||||
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),resId);
|
||||
bitmapDrawable = new BitmapDrawable(bitmap);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public ImageView getTitleView(int tab) {
|
||||
View tabView = mTabsContainer.getChildAt(tab);
|
||||
ImageView iv_tab_title = (ImageView) tabView.findViewById(R.id.iv_tab_title);
|
||||
return iv_tab_title;
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
|
||||
// show MsgTipView
|
||||
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private SparseArray<Boolean> mInitSetMap = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* 显示未读消息
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
* @param num num小于等于0显示红点,num大于0显示数字
|
||||
*/
|
||||
public void showMsg(int position, int num) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
UnreadMsgUtils.show(tipView, num);
|
||||
|
||||
if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMsgMargin(position, 4, 2);
|
||||
mInitSetMap.put(position, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示未读红点
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
*/
|
||||
public void showDot(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
showMsg(position, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏未读消息
|
||||
*/
|
||||
public void hideMsg(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
tipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳
|
||||
*/
|
||||
public void setMsgMargin(int position, float leftPadding, float bottomPadding) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
ImageView iv_tab_title = (ImageView) tabView.findViewById(R.id.iv_tab_title);
|
||||
// float textWidth = mTextPaint.measureText(iv_tab_title.getText().toString());
|
||||
float imgWidth = iv_tab_title.getMeasuredWidth();
|
||||
float textHeight = mTextPaint.descent() - mTextPaint.ascent();
|
||||
MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams();
|
||||
lp.leftMargin = mTabWidth >= 0 ? (int) (mTabWidth / 2 + imgWidth / 2 + dp2px(leftPadding)) : (int) (mTabPadding + imgWidth + dp2px(leftPadding));
|
||||
lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : 0;
|
||||
tipView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置
|
||||
*/
|
||||
public MsgView getMsgView(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
return tipView;
|
||||
}
|
||||
|
||||
private OnTabSelectListener mListener;
|
||||
|
||||
public void setOnTabSelectListener(OnTabSelectListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
class InnerPagerAdapter extends FragmentPagerAdapter {
|
||||
private ArrayList<Fragment> fragments = new ArrayList<>();
|
||||
private String[] titles;
|
||||
|
||||
public InnerPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragments, String[] titles) {
|
||||
super(fm);
|
||||
this.fragments = fragments;
|
||||
this.titles = titles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return fragments.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return titles[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return fragments.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
// 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁
|
||||
// super.destroyItem(container, position, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(Object object) {
|
||||
return PagerAdapter.POSITION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("instanceState", super.onSaveInstanceState());
|
||||
bundle.putInt("mCurrentTab", mCurrentTab);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
mCurrentTab = bundle.getInt("mCurrentTab");
|
||||
state = bundle.getParcelable("instanceState");
|
||||
if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) {
|
||||
updateTabSelection(mCurrentTab);
|
||||
scrollToCurrentTab();
|
||||
}
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
|
||||
protected int dp2px(float dp) {
|
||||
final float scale = mContext.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
protected int sp2px(float sp) {
|
||||
final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (sp * scale + 0.5f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,980 @@
|
||||
package com.example.moduletablayout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.example.moduletablayout.listener.OnTabSelectListener;
|
||||
import com.example.moduletablayout.utils.UnreadMsgUtils;
|
||||
import com.example.moduletablayout.widget.MsgView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 滑动TabLayout,对于ViewPager的依赖性强
|
||||
*/
|
||||
public class CustomSlidingTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener {
|
||||
private Context mContext;
|
||||
private ViewPager mViewPager;
|
||||
private ArrayList<String> mTitles;
|
||||
private LinearLayout mTabsContainer;
|
||||
private int mCurrentTab;
|
||||
private float mCurrentPositionOffset;
|
||||
private int mTabCount;
|
||||
/**
|
||||
* 用于绘制显示器
|
||||
*/
|
||||
private Rect mIndicatorRect = new Rect();
|
||||
/**
|
||||
* 用于实现滚动居中
|
||||
*/
|
||||
private Rect mTabRect = new Rect();
|
||||
private GradientDrawable mIndicatorDrawable = new GradientDrawable();
|
||||
// private GradientDrawable mIndicatorDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[]{Color.parseColor("#45D08C"), Color.parseColor("#45D08C")});
|
||||
|
||||
|
||||
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Path mTrianglePath = new Path();
|
||||
private static final int STYLE_NORMAL = 0;
|
||||
private static final int STYLE_TRIANGLE = 1;
|
||||
private static final int STYLE_BLOCK = 2;
|
||||
private int mIndicatorStyle = STYLE_NORMAL;
|
||||
|
||||
private float mTabPadding;
|
||||
private boolean mTabSpaceEqual;
|
||||
private float mTabWidth;
|
||||
|
||||
/**
|
||||
* indicator
|
||||
*/
|
||||
private int mIndicatorColor;
|
||||
private float mIndicatorHeight;
|
||||
private float mIndicatorWidth;
|
||||
private float mIndicatorCornerRadius;
|
||||
private float mIndicatorMarginLeft;
|
||||
private float mIndicatorMarginTop;
|
||||
private float mIndicatorMarginRight;
|
||||
private float mIndicatorMarginBottom;
|
||||
private int mIndicatorGravity;
|
||||
private boolean mIndicatorWidthEqualTitle;
|
||||
|
||||
/**
|
||||
* underline
|
||||
*/
|
||||
private int mUnderlineColor;
|
||||
private float mUnderlineHeight;
|
||||
private int mUnderlineGravity;
|
||||
|
||||
/**
|
||||
* divider
|
||||
*/
|
||||
private int mDividerColor;
|
||||
private float mDividerWidth;
|
||||
private float mDividerPadding;
|
||||
|
||||
/**
|
||||
* title
|
||||
*/
|
||||
private static final int TEXT_BOLD_NONE = 0;
|
||||
private static final int TEXT_BOLD_WHEN_SELECT = 1;
|
||||
private static final int TEXT_BOLD_BOTH = 2;
|
||||
private float mTextsize;
|
||||
private float mTextSelectedSize;
|
||||
private int mTextSelectColor;
|
||||
private int mTextUnselectColor;
|
||||
private int mTextBold;
|
||||
private boolean mTextAllCaps;
|
||||
|
||||
private int mLastScrollX;
|
||||
private int mHeight;
|
||||
private boolean mSnapOnTabClick;
|
||||
private boolean showCateIndicator;
|
||||
private Bitmap mBitmap;
|
||||
private Paint mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
public CustomSlidingTabLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public CustomSlidingTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomSlidingTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.tab_x);
|
||||
// mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.flyco_ic_indicator_selected_category);
|
||||
setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口
|
||||
setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
|
||||
this.mContext = context;
|
||||
mTabsContainer = new LinearLayout(context);
|
||||
addView(mTabsContainer);
|
||||
|
||||
obtainAttributes(context, attrs);
|
||||
if (showCateIndicator) {
|
||||
// mIndicatorDrawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, new int[]{Color.parseColor("#FF6FD0FF"), Color.TRANSPARENT});
|
||||
mIndicatorDrawable = new GradientDrawable();
|
||||
}
|
||||
|
||||
//get layout_height
|
||||
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
|
||||
|
||||
if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) {
|
||||
} else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) {
|
||||
} else {
|
||||
int[] systemAttrs = {android.R.attr.layout_height};
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
|
||||
mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void obtainAttributes(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabLayout);
|
||||
|
||||
mIndicatorStyle = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_style, STYLE_NORMAL);
|
||||
mIndicatorColor = ta.getColor(R.styleable.SlidingTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff"));
|
||||
mIndicatorHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_height,
|
||||
dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2)));
|
||||
mIndicatorWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1));
|
||||
mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0));
|
||||
mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_left, dp2px(0));
|
||||
mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_right, dp2px(0));
|
||||
mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_gravity, Gravity.BOTTOM);
|
||||
mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingTabLayout_tl_indicator_width_equal_title, false);
|
||||
|
||||
mUnderlineColor = ta.getColor(R.styleable.SlidingTabLayout_tl_underline_color, Color.parseColor("#ffffff"));
|
||||
mUnderlineHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_underline_height, dp2px(0));
|
||||
mUnderlineGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_underline_gravity, Gravity.BOTTOM);
|
||||
|
||||
mDividerColor = ta.getColor(R.styleable.SlidingTabLayout_tl_divider_color, Color.parseColor("#ffffff"));
|
||||
mDividerWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_width, dp2px(0));
|
||||
mDividerPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_padding, dp2px(12));
|
||||
|
||||
mTextsize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textsize, sp2px(14));
|
||||
mTextSelectedSize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textSelectedSize, mTextsize * 1.3f);
|
||||
mTextSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textSelectColor, Color.parseColor("#ffffff"));
|
||||
mTextUnselectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textUnselectColor, Color.parseColor("#AAffffff"));
|
||||
mTextBold = ta.getInt(R.styleable.SlidingTabLayout_tl_textBold, TEXT_BOLD_NONE);
|
||||
mTextAllCaps = ta.getBoolean(R.styleable.SlidingTabLayout_tl_textAllCaps, false);
|
||||
|
||||
mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingTabLayout_tl_tab_space_equal, false);
|
||||
mTabWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_width, dp2px(-1));
|
||||
mTabPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20));
|
||||
showCateIndicator = ta.getBoolean(R.styleable.SlidingTabLayout_tl_showCateIndicator, false);
|
||||
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联ViewPager
|
||||
*/
|
||||
public void setViewPager(ViewPager vp) {
|
||||
if (vp == null || vp.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager or ViewPager rightAdapter can not be NULL !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况
|
||||
*/
|
||||
public void setViewPager(ViewPager vp, String[] titles) {
|
||||
if (vp == null || vp.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager or ViewPager rightAdapter can not be NULL !");
|
||||
}
|
||||
|
||||
if (titles == null || titles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be EMPTY !");
|
||||
}
|
||||
|
||||
if (titles.length != vp.getAdapter().getCount()) {
|
||||
throw new IllegalStateException("Titles length must be the same as the page count !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
mTitles = new ArrayList<>();
|
||||
Collections.addAll(mTitles, titles);
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联ViewPager,用于连适配器都不想自己实例化的情况
|
||||
*/
|
||||
public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList<Fragment> fragments) {
|
||||
if (vp == null) {
|
||||
throw new IllegalStateException("ViewPager can not be NULL !");
|
||||
}
|
||||
|
||||
if (titles == null || titles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be EMPTY !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles));
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新数据
|
||||
*/
|
||||
public void notifyDataSetChanged() {
|
||||
mTabsContainer.removeAllViews();
|
||||
this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size();
|
||||
View tabView;
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
tabView = View.inflate(mContext, R.layout.flyco_layout_tab, null);
|
||||
CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i);
|
||||
addTab(i, pageTitle.toString(), tabView);
|
||||
}
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void addNewTab(String title) {
|
||||
View tabView = View.inflate(mContext, R.layout.flyco_layout_tab, null);
|
||||
if (mTitles != null) {
|
||||
mTitles.add(title);
|
||||
}
|
||||
|
||||
CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(mTabCount) : mTitles.get(mTabCount);
|
||||
addTab(mTabCount, pageTitle.toString(), tabView);
|
||||
this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size();
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建并添加tab
|
||||
*/
|
||||
private void addTab(final int position, String title, View tabView) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
if (tv_tab_title != null) {
|
||||
if (title != null) tv_tab_title.setText(title);
|
||||
}
|
||||
|
||||
tabView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = mTabsContainer.indexOfChild(v);
|
||||
if (position != -1) {
|
||||
if (mViewPager.getCurrentItem() != position) {
|
||||
if (mSnapOnTabClick) {
|
||||
mViewPager.setCurrentItem(position, false);
|
||||
} else {
|
||||
mViewPager.setCurrentItem(position);
|
||||
}
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onTabSelect(position);
|
||||
}
|
||||
} else {
|
||||
if (mListener != null) {
|
||||
mListener.onTabReselect(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** 每一个Tab的布局参数 */
|
||||
LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?
|
||||
new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
|
||||
new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
if (mTabWidth > 0) {
|
||||
lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
|
||||
mTabsContainer.addView(tabView, position, lp_tab);
|
||||
}
|
||||
|
||||
private void updateTabStyles() {
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
View v = mTabsContainer.getChildAt(i);
|
||||
// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom());
|
||||
TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title);
|
||||
if (tv_tab_title != null) {
|
||||
tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor);
|
||||
tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize);
|
||||
tv_tab_title.setPadding((int) mTabPadding, 5, (int) mTabPadding, 5);
|
||||
if (mTextAllCaps) {
|
||||
tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase());
|
||||
}
|
||||
|
||||
if (mTextBold == TEXT_BOLD_BOTH) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(true);
|
||||
} else if (mTextBold == TEXT_BOLD_NONE) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
/**
|
||||
* position:当前View的位置
|
||||
* mCurrentPositionOffset:当前View的偏移量比例.[0,1)
|
||||
*/
|
||||
this.mCurrentTab = position;
|
||||
this.mCurrentPositionOffset = positionOffset;
|
||||
scrollToCurrentTab();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
updateTabSelection(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* HorizontalScrollView滚到当前tab,并且居中显示
|
||||
*/
|
||||
private void scrollToCurrentTab() {
|
||||
if (mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth());
|
||||
/**当前Tab的left+当前Tab的Width乘以positionOffset*/
|
||||
int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset;
|
||||
|
||||
if (mCurrentTab > 0 || offset > 0) {
|
||||
/**HorizontalScrollView移动到当前tab,并居中*/
|
||||
newScrollX -= getWidth() / 2 - getPaddingLeft();
|
||||
calcIndicatorRect();
|
||||
newScrollX += ((mTabRect.right - mTabRect.left) / 2);
|
||||
}
|
||||
|
||||
if (newScrollX != mLastScrollX) {
|
||||
mLastScrollX = newScrollX;
|
||||
/** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量
|
||||
* x:表示离起始位置的x水平方向的偏移量
|
||||
* y:表示离起始位置的y垂直方向的偏移量
|
||||
*/
|
||||
scrollTo(newScrollX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTabSelection(int position) {
|
||||
for (int i = 0; i < mTabCount; ++i) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
final boolean isSelect = i == position;
|
||||
TextView tab_title = tabView.findViewById(R.id.tv_tab_title);
|
||||
|
||||
if (tab_title != null) {
|
||||
tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor);
|
||||
tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, isSelect ? mTextSelectedSize : mTextsize);
|
||||
// ViewCompat.animate(tab_title).setDuration(200).scaleX(isSelect ? 1.3f : 1f).scaleY(isSelect ? 1.3f : 1f).alpha(isSelect ? 1f : 0.4f).start();
|
||||
if (mTextBold == TEXT_BOLD_WHEN_SELECT) {
|
||||
tab_title.getPaint().setFakeBoldText(isSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float margin;
|
||||
|
||||
private void calcIndicatorRect() {
|
||||
View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
float left = currentTabView.getLeft();
|
||||
float right = currentTabView.getRight();
|
||||
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
TextView tab_title = (TextView) currentTabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float textWidth = mTextPaint.measureText(tab_title.getText().toString());
|
||||
margin = (right - left - textWidth) / 2;
|
||||
}
|
||||
|
||||
if (this.mCurrentTab < mTabCount - 1) {
|
||||
View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1);
|
||||
float nextTabLeft = nextTabView.getLeft();
|
||||
float nextTabRight = nextTabView.getRight();
|
||||
|
||||
left = left + mCurrentPositionOffset * (nextTabLeft - left);
|
||||
right = right + mCurrentPositionOffset * (nextTabRight - right);
|
||||
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
TextView next_tab_title = (TextView) nextTabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString());
|
||||
float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2;
|
||||
margin = margin + mCurrentPositionOffset * (nextMargin - margin);
|
||||
}
|
||||
}
|
||||
|
||||
mIndicatorRect.left = (int) left;
|
||||
mIndicatorRect.right = (int) right;
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
mIndicatorRect.left = (int) (left + margin - 1);
|
||||
mIndicatorRect.right = (int) (right - margin - 1);
|
||||
}
|
||||
|
||||
mTabRect.left = (int) left;
|
||||
mTabRect.right = (int) right;
|
||||
|
||||
if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip
|
||||
|
||||
} else {//indicatorWidth大于0时,圆角矩形以及三角形
|
||||
float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2;
|
||||
|
||||
if (this.mCurrentTab < mTabCount - 1) {
|
||||
View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1);
|
||||
indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2);
|
||||
}
|
||||
|
||||
mIndicatorRect.left = (int) indicatorLeft;
|
||||
mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (isInEditMode() || mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int height = getHeight();
|
||||
int paddingLeft = getPaddingLeft();
|
||||
// draw divider
|
||||
if (mDividerWidth > 0) {
|
||||
mDividerPaint.setStrokeWidth(mDividerWidth);
|
||||
mDividerPaint.setColor(mDividerColor);
|
||||
for (int i = 0; i < mTabCount - 1; i++) {
|
||||
View tab = mTabsContainer.getChildAt(i);
|
||||
canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
// draw underline
|
||||
if (mUnderlineHeight > 0) {
|
||||
mRectPaint.setColor(mUnderlineColor);
|
||||
if (mUnderlineGravity == Gravity.BOTTOM) {
|
||||
canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint);
|
||||
} else {
|
||||
canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint);
|
||||
}
|
||||
}
|
||||
|
||||
//draw indicator line
|
||||
|
||||
calcIndicatorRect();
|
||||
if (mIndicatorStyle == STYLE_TRIANGLE) {
|
||||
if (mIndicatorHeight > 0) {
|
||||
mTrianglePaint.setColor(mIndicatorColor);
|
||||
mTrianglePath.reset();
|
||||
mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height);
|
||||
mTrianglePath.close();
|
||||
canvas.drawPath(mTrianglePath, mTrianglePaint);
|
||||
}
|
||||
} else if (mIndicatorStyle == STYLE_BLOCK) {
|
||||
if (mIndicatorHeight < 0) {
|
||||
mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) {
|
||||
mIndicatorCornerRadius = mIndicatorHeight / 2;
|
||||
}
|
||||
|
||||
// mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight),
|
||||
(int) (mIndicatorMarginTop + mIndicatorHeight));
|
||||
mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
}
|
||||
} else {
|
||||
/* mRectPaint.setColor(mIndicatorColor);
|
||||
calcIndicatorRect();
|
||||
canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight,
|
||||
mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
// mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
if (mIndicatorGravity == Gravity.BOTTOM) {
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
height - (int) mIndicatorMarginBottom);
|
||||
} else {
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
(int) mIndicatorHeight + (int) mIndicatorMarginTop);
|
||||
}
|
||||
mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
if (showCateIndicator) {
|
||||
canvas.drawBitmap(mBitmap, mIndicatorRect.left + mIndicatorMarginLeft
|
||||
, mIndicatorMarginTop, mBitmapPaint);
|
||||
} else {
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
public void setCurrentTab(int currentTab) {
|
||||
if (mCurrentTab == currentTab) {
|
||||
updateTabSelection(currentTab);
|
||||
}
|
||||
this.mCurrentTab = currentTab;
|
||||
mViewPager.setCurrentItem(currentTab);
|
||||
|
||||
}
|
||||
|
||||
public void setCurrentTab(int currentTab, boolean smoothScroll) {
|
||||
this.mCurrentTab = currentTab;
|
||||
mViewPager.setCurrentItem(currentTab, smoothScroll);
|
||||
}
|
||||
|
||||
public void setIndicatorStyle(int indicatorStyle) {
|
||||
this.mIndicatorStyle = indicatorStyle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTabPadding(float tabPadding) {
|
||||
this.mTabPadding = dp2px(tabPadding);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabSpaceEqual(boolean tabSpaceEqual) {
|
||||
this.mTabSpaceEqual = tabSpaceEqual;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabWidth(float tabWidth) {
|
||||
this.mTabWidth = dp2px(tabWidth);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int indicatorColor) {
|
||||
this.mIndicatorColor = indicatorColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorHeight(float indicatorHeight) {
|
||||
this.mIndicatorHeight = dp2px(indicatorHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidth(float indicatorWidth) {
|
||||
this.mIndicatorWidth = dp2px(indicatorWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorCornerRadius(float indicatorCornerRadius) {
|
||||
this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorGravity(int indicatorGravity) {
|
||||
this.mIndicatorGravity = indicatorGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop,
|
||||
float indicatorMarginRight, float indicatorMarginBottom) {
|
||||
this.mIndicatorMarginLeft = indicatorMarginLeft;
|
||||
this.mIndicatorMarginTop = indicatorMarginTop;
|
||||
this.mIndicatorMarginRight = indicatorMarginRight;
|
||||
this.mIndicatorMarginBottom = indicatorMarginBottom;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) {
|
||||
this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineColor(int underlineColor) {
|
||||
this.mUnderlineColor = underlineColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineHeight(float underlineHeight) {
|
||||
this.mUnderlineHeight = dp2px(underlineHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineGravity(int underlineGravity) {
|
||||
this.mUnderlineGravity = underlineGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerColor(int dividerColor) {
|
||||
this.mDividerColor = dividerColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerWidth(float dividerWidth) {
|
||||
this.mDividerWidth = dp2px(dividerWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerPadding(float dividerPadding) {
|
||||
this.mDividerPadding = dp2px(dividerPadding);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTextsize(float textsize) {
|
||||
this.mTextsize = sp2px(textsize);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextSelectColor(int textSelectColor) {
|
||||
this.mTextSelectColor = textSelectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextUnselectColor(int textUnselectColor) {
|
||||
this.mTextUnselectColor = textUnselectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextBold(int textBold) {
|
||||
this.mTextBold = textBold;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextAllCaps(boolean textAllCaps) {
|
||||
this.mTextAllCaps = textAllCaps;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setSnapOnTabClick(boolean snapOnTabClick) {
|
||||
mSnapOnTabClick = snapOnTabClick;
|
||||
}
|
||||
|
||||
|
||||
public int getTabCount() {
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
public int getCurrentTab() {
|
||||
return mCurrentTab;
|
||||
}
|
||||
|
||||
public int getIndicatorStyle() {
|
||||
return mIndicatorStyle;
|
||||
}
|
||||
|
||||
public float getTabPadding() {
|
||||
return mTabPadding;
|
||||
}
|
||||
|
||||
public boolean isTabSpaceEqual() {
|
||||
return mTabSpaceEqual;
|
||||
}
|
||||
|
||||
public float getTabWidth() {
|
||||
return mTabWidth;
|
||||
}
|
||||
|
||||
public int getIndicatorColor() {
|
||||
return mIndicatorColor;
|
||||
}
|
||||
|
||||
public float getIndicatorHeight() {
|
||||
return mIndicatorHeight;
|
||||
}
|
||||
|
||||
public float getIndicatorWidth() {
|
||||
return mIndicatorWidth;
|
||||
}
|
||||
|
||||
public float getIndicatorCornerRadius() {
|
||||
return mIndicatorCornerRadius;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginLeft() {
|
||||
return mIndicatorMarginLeft;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginTop() {
|
||||
return mIndicatorMarginTop;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginRight() {
|
||||
return mIndicatorMarginRight;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginBottom() {
|
||||
return mIndicatorMarginBottom;
|
||||
}
|
||||
|
||||
public int getUnderlineColor() {
|
||||
return mUnderlineColor;
|
||||
}
|
||||
|
||||
public float getUnderlineHeight() {
|
||||
return mUnderlineHeight;
|
||||
}
|
||||
|
||||
public int getDividerColor() {
|
||||
return mDividerColor;
|
||||
}
|
||||
|
||||
public float getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
public float getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
public float getTextsize() {
|
||||
return mTextsize;
|
||||
}
|
||||
|
||||
public int getTextSelectColor() {
|
||||
return mTextSelectColor;
|
||||
}
|
||||
|
||||
public int getTextUnselectColor() {
|
||||
return mTextUnselectColor;
|
||||
}
|
||||
|
||||
public int getTextBold() {
|
||||
return mTextBold;
|
||||
}
|
||||
|
||||
public boolean isTextAllCaps() {
|
||||
return mTextAllCaps;
|
||||
}
|
||||
|
||||
public void setIndicatorDrawable(GradientDrawable mIndicatorDrawable) {
|
||||
this.mIndicatorDrawable = mIndicatorDrawable;
|
||||
}
|
||||
|
||||
public TextView getTitleView(int tab) {
|
||||
View tabView = mTabsContainer.getChildAt(tab);
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
return tv_tab_title;
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
|
||||
// show MsgTipView
|
||||
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private SparseArray<Boolean> mInitSetMap = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* 显示未读消息
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
* @param num num小于等于0显示红点,num大于0显示数字
|
||||
*/
|
||||
public void showMsg(int position, int num) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
UnreadMsgUtils.show(tipView, num);
|
||||
|
||||
if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMsgMargin(position, 4, 2);
|
||||
mInitSetMap.put(position, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示未读红点
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
*/
|
||||
public void showDot(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
showMsg(position, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏未读消息
|
||||
*/
|
||||
public void hideMsg(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
tipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳
|
||||
*/
|
||||
public void setMsgMargin(int position, float leftPadding, float bottomPadding) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString());
|
||||
float textHeight = mTextPaint.descent() - mTextPaint.ascent();
|
||||
MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams();
|
||||
lp.leftMargin = mTabWidth >= 0 ? (int) (mTabWidth / 2 + textWidth / 2 + dp2px(leftPadding)) : (int) (mTabPadding + textWidth + dp2px(leftPadding));
|
||||
lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : 0;
|
||||
tipView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置
|
||||
*/
|
||||
public MsgView getMsgView(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
return tipView;
|
||||
}
|
||||
|
||||
private OnTabSelectListener mListener;
|
||||
|
||||
public void setOnTabSelectListener(OnTabSelectListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
class InnerPagerAdapter extends FragmentPagerAdapter {
|
||||
private ArrayList<Fragment> fragments = new ArrayList<>();
|
||||
private String[] titles;
|
||||
|
||||
public InnerPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragments, String[] titles) {
|
||||
super(fm);
|
||||
this.fragments = fragments;
|
||||
this.titles = titles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return fragments.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return titles[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return fragments.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
// 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁
|
||||
// super.destroyItem(container, position, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(Object object) {
|
||||
return PagerAdapter.POSITION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("instanceState", super.onSaveInstanceState());
|
||||
bundle.putInt("mCurrentTab", mCurrentTab);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
mCurrentTab = bundle.getInt("mCurrentTab");
|
||||
state = bundle.getParcelable("instanceState");
|
||||
if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) {
|
||||
updateTabSelection(mCurrentTab);
|
||||
scrollToCurrentTab();
|
||||
}
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
|
||||
protected int dp2px(float dp) {
|
||||
final float scale = mContext.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
protected int sp2px(float sp) {
|
||||
final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (sp * scale + 0.5f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,755 @@
|
||||
package com.example.moduletablayout;
|
||||
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
|
||||
import com.example.moduletablayout.listener.OnTabSelectListener;
|
||||
import com.example.moduletablayout.utils.FragmentChangeManager;
|
||||
import com.example.moduletablayout.utils.UnreadMsgUtils;
|
||||
import com.example.moduletablayout.widget.MsgView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SegmentTabLayout extends FrameLayout implements ValueAnimator.AnimatorUpdateListener {
|
||||
private Context mContext;
|
||||
private String[] mTitles;
|
||||
private LinearLayout mTabsContainer;
|
||||
private int mCurrentTab;
|
||||
private int mLastTab;
|
||||
private int mTabCount;
|
||||
/** 用于绘制显示器 */
|
||||
private Rect mIndicatorRect = new Rect();
|
||||
private GradientDrawable mIndicatorDrawable = new GradientDrawable();
|
||||
private GradientDrawable mRectDrawable = new GradientDrawable();
|
||||
|
||||
private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
private float mTabPadding;
|
||||
private boolean mTabSpaceEqual;
|
||||
private float mTabWidth;
|
||||
|
||||
/** indicator */
|
||||
private int mIndicatorColor;
|
||||
private float mIndicatorHeight;
|
||||
private float mIndicatorCornerRadius;
|
||||
private float mIndicatorMarginLeft;
|
||||
private float mIndicatorMarginTop;
|
||||
private float mIndicatorMarginRight;
|
||||
private float mIndicatorMarginBottom;
|
||||
private long mIndicatorAnimDuration;
|
||||
private boolean mIndicatorAnimEnable;
|
||||
private boolean mIndicatorBounceEnable;
|
||||
|
||||
/** divider */
|
||||
private int mDividerColor;
|
||||
private float mDividerWidth;
|
||||
private float mDividerPadding;
|
||||
|
||||
/** title */
|
||||
private static final int TEXT_BOLD_NONE = 0;
|
||||
private static final int TEXT_BOLD_WHEN_SELECT = 1;
|
||||
private static final int TEXT_BOLD_BOTH = 2;
|
||||
private float mTextsize;
|
||||
private int mTextSelectColor;
|
||||
private int mTextUnselectColor;
|
||||
private int mTextBold;
|
||||
private boolean mTextAllCaps;
|
||||
|
||||
private int mBarColor;
|
||||
private int mBarStrokeColor;
|
||||
private float mBarStrokeWidth;
|
||||
|
||||
private int mHeight;
|
||||
|
||||
/** anim */
|
||||
private ValueAnimator mValueAnimator;
|
||||
private OvershootInterpolator mInterpolator = new OvershootInterpolator(0.8f);
|
||||
|
||||
private FragmentChangeManager mFragmentChangeManager;
|
||||
private float[] mRadiusArr = new float[8];
|
||||
|
||||
public SegmentTabLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public SegmentTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SegmentTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
|
||||
this.mContext = context;
|
||||
mTabsContainer = new LinearLayout(context);
|
||||
addView(mTabsContainer);
|
||||
|
||||
obtainAttributes(context, attrs);
|
||||
|
||||
//get layout_height
|
||||
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
|
||||
|
||||
//create ViewPager
|
||||
if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) {
|
||||
} else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) {
|
||||
} else {
|
||||
int[] systemAttrs = {android.R.attr.layout_height};
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
|
||||
mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
mValueAnimator = ValueAnimator.ofObject(new PointEvaluator(), mLastP, mCurrentP);
|
||||
mValueAnimator.addUpdateListener(this);
|
||||
}
|
||||
|
||||
private void obtainAttributes(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentTabLayout);
|
||||
|
||||
mIndicatorColor = ta.getColor(R.styleable.SegmentTabLayout_tl_indicator_color, Color.parseColor("#222831"));
|
||||
mIndicatorHeight = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_height, -1);
|
||||
mIndicatorCornerRadius = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_corner_radius, -1);
|
||||
mIndicatorMarginLeft = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_left, dp2px(0));
|
||||
mIndicatorMarginTop = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_top, 0);
|
||||
mIndicatorMarginRight = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_right, dp2px(0));
|
||||
mIndicatorMarginBottom = ta.getDimension(R.styleable.SegmentTabLayout_tl_indicator_margin_bottom, 0);
|
||||
mIndicatorAnimEnable = ta.getBoolean(R.styleable.SegmentTabLayout_tl_indicator_anim_enable, false);
|
||||
mIndicatorBounceEnable = ta.getBoolean(R.styleable.SegmentTabLayout_tl_indicator_bounce_enable, true);
|
||||
mIndicatorAnimDuration = ta.getInt(R.styleable.SegmentTabLayout_tl_indicator_anim_duration, -1);
|
||||
|
||||
mDividerColor = ta.getColor(R.styleable.SegmentTabLayout_tl_divider_color, mIndicatorColor);
|
||||
mDividerWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_divider_width, dp2px(1));
|
||||
mDividerPadding = ta.getDimension(R.styleable.SegmentTabLayout_tl_divider_padding, 0);
|
||||
|
||||
mTextsize = ta.getDimension(R.styleable.SegmentTabLayout_tl_textsize, sp2px(13f));
|
||||
mTextSelectColor = ta.getColor(R.styleable.SegmentTabLayout_tl_textSelectColor, Color.parseColor("#ffffff"));
|
||||
mTextUnselectColor = ta.getColor(R.styleable.SegmentTabLayout_tl_textUnselectColor, mIndicatorColor);
|
||||
mTextBold = ta.getInt(R.styleable.SegmentTabLayout_tl_textBold, TEXT_BOLD_NONE);
|
||||
mTextAllCaps = ta.getBoolean(R.styleable.SegmentTabLayout_tl_textAllCaps, false);
|
||||
|
||||
mTabSpaceEqual = ta.getBoolean(R.styleable.SegmentTabLayout_tl_tab_space_equal, true);
|
||||
mTabWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_tab_width, dp2px(-1));
|
||||
mTabPadding = ta.getDimension(R.styleable.SegmentTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(10));
|
||||
|
||||
mBarColor = ta.getColor(R.styleable.SegmentTabLayout_tl_bar_color, Color.TRANSPARENT);
|
||||
mBarStrokeColor = ta.getColor(R.styleable.SegmentTabLayout_tl_bar_stroke_color, mIndicatorColor);
|
||||
mBarStrokeWidth = ta.getDimension(R.styleable.SegmentTabLayout_tl_bar_stroke_width, dp2px(1));
|
||||
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
public void setTabData(String[] titles) {
|
||||
if (titles == null || titles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be NULL or EMPTY !");
|
||||
}
|
||||
|
||||
this.mTitles = titles;
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/** 关联数据支持同时切换fragments */
|
||||
public void setTabData(String[] titles, FragmentActivity fa, int containerViewId, ArrayList<Fragment> fragments) {
|
||||
mFragmentChangeManager = new FragmentChangeManager(fa.getSupportFragmentManager(), containerViewId, fragments);
|
||||
setTabData(titles);
|
||||
}
|
||||
|
||||
/** 更新数据 */
|
||||
public void notifyDataSetChanged() {
|
||||
mTabsContainer.removeAllViews();
|
||||
this.mTabCount = mTitles.length;
|
||||
View tabView;
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
tabView = View.inflate(mContext, R.layout.layout_tab_segment, null);
|
||||
tabView.setTag(i);
|
||||
addTab(i, tabView);
|
||||
}
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
/** 创建并添加tab */
|
||||
private void addTab(final int position, View tabView) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
tv_tab_title.setText(mTitles[position]);
|
||||
|
||||
tabView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = (Integer) v.getTag();
|
||||
if (mCurrentTab != position) {
|
||||
setCurrentTab(position);
|
||||
if (mListener != null) {
|
||||
mListener.onTabSelect(position);
|
||||
}
|
||||
} else {
|
||||
if (mListener != null) {
|
||||
mListener.onTabReselect(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** 每一个Tab的布局参数 */
|
||||
LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?
|
||||
new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
|
||||
new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
if (mTabWidth > 0) {
|
||||
lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
mTabsContainer.addView(tabView, position, lp_tab);
|
||||
}
|
||||
|
||||
private void updateTabStyles() {
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
tabView.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor);
|
||||
tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize);
|
||||
// tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
|
||||
if (mTextAllCaps) {
|
||||
tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase());
|
||||
}
|
||||
|
||||
if (mTextBold == TEXT_BOLD_BOTH) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(true);
|
||||
} else if (mTextBold == TEXT_BOLD_NONE) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTabSelection(int position) {
|
||||
for (int i = 0; i < mTabCount; ++i) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
final boolean isSelect = i == position;
|
||||
TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor);
|
||||
if (mTextBold == TEXT_BOLD_WHEN_SELECT) {
|
||||
tab_title.getPaint().setFakeBoldText(isSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calcOffset() {
|
||||
final View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
mCurrentP.left = currentTabView.getLeft();
|
||||
mCurrentP.right = currentTabView.getRight();
|
||||
|
||||
final View lastTabView = mTabsContainer.getChildAt(this.mLastTab);
|
||||
mLastP.left = lastTabView.getLeft();
|
||||
mLastP.right = lastTabView.getRight();
|
||||
|
||||
// Log.d("AAA", "mLastP--->" + mLastP.left + "&" + mLastP.right);
|
||||
// Log.d("AAA", "mCurrentP--->" + mCurrentP.left + "&" + mCurrentP.right);
|
||||
if (mLastP.left == mCurrentP.left && mLastP.right == mCurrentP.right) {
|
||||
invalidate();
|
||||
} else {
|
||||
mValueAnimator.setObjectValues(mLastP, mCurrentP);
|
||||
if (mIndicatorBounceEnable) {
|
||||
mValueAnimator.setInterpolator(mInterpolator);
|
||||
}
|
||||
|
||||
if (mIndicatorAnimDuration < 0) {
|
||||
mIndicatorAnimDuration = mIndicatorBounceEnable ? 500 : 250;
|
||||
}
|
||||
mValueAnimator.setDuration(mIndicatorAnimDuration);
|
||||
mValueAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void calcIndicatorRect() {
|
||||
View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
float left = currentTabView.getLeft();
|
||||
float right = currentTabView.getRight();
|
||||
|
||||
mIndicatorRect.left = (int) left;
|
||||
mIndicatorRect.right = (int) right;
|
||||
|
||||
if (!mIndicatorAnimEnable) {
|
||||
if (mCurrentTab == 0) {
|
||||
/**The corners are ordered top-left, top-right, bottom-right, bottom-left*/
|
||||
mRadiusArr[0] = mIndicatorCornerRadius;
|
||||
mRadiusArr[1] = mIndicatorCornerRadius;
|
||||
mRadiusArr[2] = 0;
|
||||
mRadiusArr[3] = 0;
|
||||
mRadiusArr[4] = 0;
|
||||
mRadiusArr[5] = 0;
|
||||
mRadiusArr[6] = mIndicatorCornerRadius;
|
||||
mRadiusArr[7] = mIndicatorCornerRadius;
|
||||
} else if (mCurrentTab == mTabCount - 1) {
|
||||
/**The corners are ordered top-left, top-right, bottom-right, bottom-left*/
|
||||
mRadiusArr[0] = 0;
|
||||
mRadiusArr[1] = 0;
|
||||
mRadiusArr[2] = mIndicatorCornerRadius;
|
||||
mRadiusArr[3] = mIndicatorCornerRadius;
|
||||
mRadiusArr[4] = mIndicatorCornerRadius;
|
||||
mRadiusArr[5] = mIndicatorCornerRadius;
|
||||
mRadiusArr[6] = 0;
|
||||
mRadiusArr[7] = 0;
|
||||
} else {
|
||||
/**The corners are ordered top-left, top-right, bottom-right, bottom-left*/
|
||||
mRadiusArr[0] = 0;
|
||||
mRadiusArr[1] = 0;
|
||||
mRadiusArr[2] = 0;
|
||||
mRadiusArr[3] = 0;
|
||||
mRadiusArr[4] = 0;
|
||||
mRadiusArr[5] = 0;
|
||||
mRadiusArr[6] = 0;
|
||||
mRadiusArr[7] = 0;
|
||||
}
|
||||
} else {
|
||||
/**The corners are ordered top-left, top-right, bottom-right, bottom-left*/
|
||||
mRadiusArr[0] = mIndicatorCornerRadius;
|
||||
mRadiusArr[1] = mIndicatorCornerRadius;
|
||||
mRadiusArr[2] = mIndicatorCornerRadius;
|
||||
mRadiusArr[3] = mIndicatorCornerRadius;
|
||||
mRadiusArr[4] = mIndicatorCornerRadius;
|
||||
mRadiusArr[5] = mIndicatorCornerRadius;
|
||||
mRadiusArr[6] = mIndicatorCornerRadius;
|
||||
mRadiusArr[7] = mIndicatorCornerRadius;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
IndicatorPoint p = (IndicatorPoint) animation.getAnimatedValue();
|
||||
mIndicatorRect.left = (int) p.left;
|
||||
mIndicatorRect.right = (int) p.right;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private boolean mIsFirstDraw = true;
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (isInEditMode() || mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int height = getHeight();
|
||||
int paddingLeft = getPaddingLeft();
|
||||
|
||||
if (mIndicatorHeight < 0) {
|
||||
mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom;
|
||||
}
|
||||
|
||||
if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) {
|
||||
mIndicatorCornerRadius = mIndicatorHeight / 2;
|
||||
}
|
||||
|
||||
//draw rect
|
||||
mRectDrawable.setColor(mBarColor);
|
||||
mRectDrawable.setStroke((int) mBarStrokeWidth, mBarStrokeColor);
|
||||
mRectDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
mRectDrawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
|
||||
mRectDrawable.draw(canvas);
|
||||
|
||||
// draw divider
|
||||
if (!mIndicatorAnimEnable && mDividerWidth > 0) {
|
||||
mDividerPaint.setStrokeWidth(mDividerWidth);
|
||||
mDividerPaint.setColor(mDividerColor);
|
||||
for (int i = 0; i < mTabCount - 1; i++) {
|
||||
View tab = mTabsContainer.getChildAt(i);
|
||||
canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//draw indicator line
|
||||
if (mIndicatorAnimEnable) {
|
||||
if (mIsFirstDraw) {
|
||||
mIsFirstDraw = false;
|
||||
calcIndicatorRect();
|
||||
}
|
||||
} else {
|
||||
calcIndicatorRect();
|
||||
}
|
||||
|
||||
mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight),
|
||||
(int) (mIndicatorMarginTop + mIndicatorHeight));
|
||||
mIndicatorDrawable.setCornerRadii(mRadiusArr);
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
public void setCurrentTab(int currentTab) {
|
||||
mLastTab = this.mCurrentTab;
|
||||
this.mCurrentTab = currentTab;
|
||||
updateTabSelection(currentTab);
|
||||
if (mFragmentChangeManager != null) {
|
||||
mFragmentChangeManager.setFragments(currentTab);
|
||||
}
|
||||
if (mIndicatorAnimEnable) {
|
||||
calcOffset();
|
||||
} else {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTabPadding(float tabPadding) {
|
||||
this.mTabPadding = dp2px(tabPadding);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabSpaceEqual(boolean tabSpaceEqual) {
|
||||
this.mTabSpaceEqual = tabSpaceEqual;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabWidth(float tabWidth) {
|
||||
this.mTabWidth = dp2px(tabWidth);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int indicatorColor) {
|
||||
this.mIndicatorColor = indicatorColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorHeight(float indicatorHeight) {
|
||||
this.mIndicatorHeight = dp2px(indicatorHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorCornerRadius(float indicatorCornerRadius) {
|
||||
this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop,
|
||||
float indicatorMarginRight, float indicatorMarginBottom) {
|
||||
this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft);
|
||||
this.mIndicatorMarginTop = dp2px(indicatorMarginTop);
|
||||
this.mIndicatorMarginRight = dp2px(indicatorMarginRight);
|
||||
this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorAnimDuration(long indicatorAnimDuration) {
|
||||
this.mIndicatorAnimDuration = indicatorAnimDuration;
|
||||
}
|
||||
|
||||
public void setIndicatorAnimEnable(boolean indicatorAnimEnable) {
|
||||
this.mIndicatorAnimEnable = indicatorAnimEnable;
|
||||
}
|
||||
|
||||
public void setIndicatorBounceEnable(boolean indicatorBounceEnable) {
|
||||
this.mIndicatorBounceEnable = indicatorBounceEnable;
|
||||
}
|
||||
|
||||
public void setDividerColor(int dividerColor) {
|
||||
this.mDividerColor = dividerColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerWidth(float dividerWidth) {
|
||||
this.mDividerWidth = dp2px(dividerWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerPadding(float dividerPadding) {
|
||||
this.mDividerPadding = dp2px(dividerPadding);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTextsize(float textsize) {
|
||||
this.mTextsize = sp2px(textsize);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextSelectColor(int textSelectColor) {
|
||||
this.mTextSelectColor = textSelectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextUnselectColor(int textUnselectColor) {
|
||||
this.mTextUnselectColor = textUnselectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextBold(int textBold) {
|
||||
this.mTextBold = textBold;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextAllCaps(boolean textAllCaps) {
|
||||
this.mTextAllCaps = textAllCaps;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public int getTabCount() {
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
public int getCurrentTab() {
|
||||
return mCurrentTab;
|
||||
}
|
||||
|
||||
public float getTabPadding() {
|
||||
return mTabPadding;
|
||||
}
|
||||
|
||||
public boolean isTabSpaceEqual() {
|
||||
return mTabSpaceEqual;
|
||||
}
|
||||
|
||||
public float getTabWidth() {
|
||||
return mTabWidth;
|
||||
}
|
||||
|
||||
public int getIndicatorColor() {
|
||||
return mIndicatorColor;
|
||||
}
|
||||
|
||||
public float getIndicatorHeight() {
|
||||
return mIndicatorHeight;
|
||||
}
|
||||
|
||||
public float getIndicatorCornerRadius() {
|
||||
return mIndicatorCornerRadius;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginLeft() {
|
||||
return mIndicatorMarginLeft;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginTop() {
|
||||
return mIndicatorMarginTop;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginRight() {
|
||||
return mIndicatorMarginRight;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginBottom() {
|
||||
return mIndicatorMarginBottom;
|
||||
}
|
||||
|
||||
public long getIndicatorAnimDuration() {
|
||||
return mIndicatorAnimDuration;
|
||||
}
|
||||
|
||||
public boolean isIndicatorAnimEnable() {
|
||||
return mIndicatorAnimEnable;
|
||||
}
|
||||
|
||||
public boolean isIndicatorBounceEnable() {
|
||||
return mIndicatorBounceEnable;
|
||||
}
|
||||
|
||||
public int getDividerColor() {
|
||||
return mDividerColor;
|
||||
}
|
||||
|
||||
public float getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
public float getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
public float getTextsize() {
|
||||
return mTextsize;
|
||||
}
|
||||
|
||||
public int getTextSelectColor() {
|
||||
return mTextSelectColor;
|
||||
}
|
||||
|
||||
public int getTextUnselectColor() {
|
||||
return mTextUnselectColor;
|
||||
}
|
||||
|
||||
public int getTextBold() {
|
||||
return mTextBold;
|
||||
}
|
||||
|
||||
public boolean isTextAllCaps() {
|
||||
return mTextAllCaps;
|
||||
}
|
||||
|
||||
public TextView getTitleView(int tab) {
|
||||
View tabView = mTabsContainer.getChildAt(tab);
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
return tv_tab_title;
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
// show MsgTipView
|
||||
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private SparseArray<Boolean> mInitSetMap = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* 显示未读消息
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
* @param num num小于等于0显示红点,num大于0显示数字
|
||||
*/
|
||||
public void showMsg(int position, int num) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
UnreadMsgUtils.show(tipView, num);
|
||||
|
||||
if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMsgMargin(position, 2, 2);
|
||||
|
||||
mInitSetMap.put(position, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示未读红点
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
*/
|
||||
public void showDot(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
showMsg(position, 0);
|
||||
}
|
||||
|
||||
public void hideMsg(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
tipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置提示红点偏移,注意
|
||||
* 1.控件为固定高度:参照点为tab内容的右上角
|
||||
* 2.控件高度不固定(WRAP_CONTENT):参照点为tab内容的右上角,此时高度已是红点的最高显示范围,所以这时bottomPadding其实就是topPadding
|
||||
*/
|
||||
public void setMsgMargin(int position, float leftPadding, float bottomPadding) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString());
|
||||
float textHeight = mTextPaint.descent() - mTextPaint.ascent();
|
||||
MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams();
|
||||
|
||||
lp.leftMargin = dp2px(leftPadding);
|
||||
lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : dp2px(bottomPadding);
|
||||
|
||||
tipView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 */
|
||||
public MsgView getMsgView(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
return tipView;
|
||||
}
|
||||
|
||||
private OnTabSelectListener mListener;
|
||||
|
||||
public void setOnTabSelectListener(OnTabSelectListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("instanceState", super.onSaveInstanceState());
|
||||
bundle.putInt("mCurrentTab", mCurrentTab);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
mCurrentTab = bundle.getInt("mCurrentTab");
|
||||
state = bundle.getParcelable("instanceState");
|
||||
if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) {
|
||||
updateTabSelection(mCurrentTab);
|
||||
}
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
|
||||
class IndicatorPoint {
|
||||
public float left;
|
||||
public float right;
|
||||
}
|
||||
|
||||
private IndicatorPoint mCurrentP = new IndicatorPoint();
|
||||
private IndicatorPoint mLastP = new IndicatorPoint();
|
||||
|
||||
class PointEvaluator implements TypeEvaluator<IndicatorPoint> {
|
||||
@Override
|
||||
public IndicatorPoint evaluate(float fraction, IndicatorPoint startValue, IndicatorPoint endValue) {
|
||||
float left = startValue.left + fraction * (endValue.left - startValue.left);
|
||||
float right = startValue.right + fraction * (endValue.right - startValue.right);
|
||||
IndicatorPoint point = new IndicatorPoint();
|
||||
point.left = left;
|
||||
point.right = right;
|
||||
return point;
|
||||
}
|
||||
}
|
||||
|
||||
protected int dp2px(float dp) {
|
||||
final float scale = mContext.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
protected int sp2px(float sp) {
|
||||
final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (sp * scale + 0.5f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,920 @@
|
||||
package com.example.moduletablayout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
|
||||
import com.example.moduletablayout.listener.OnTabSelectListener;
|
||||
import com.example.moduletablayout.utils.UnreadMsgUtils;
|
||||
import com.example.moduletablayout.widget.MsgView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
/** 滑动TabLayout,对于ViewPager的依赖性强 */
|
||||
public class SlidingTabLayout extends HorizontalScrollView implements ViewPager.OnPageChangeListener {
|
||||
private Context mContext;
|
||||
private ViewPager mViewPager;
|
||||
private ArrayList<String> mTitles;
|
||||
private LinearLayout mTabsContainer;
|
||||
private int mCurrentTab;
|
||||
private float mCurrentPositionOffset;
|
||||
private int mTabCount;
|
||||
/** 用于绘制显示器 */
|
||||
private Rect mIndicatorRect = new Rect();
|
||||
/** 用于实现滚动居中 */
|
||||
private Rect mTabRect = new Rect();
|
||||
private GradientDrawable mIndicatorDrawable = new GradientDrawable();
|
||||
|
||||
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mDividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mTrianglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Path mTrianglePath = new Path();
|
||||
private static final int STYLE_NORMAL = 0;
|
||||
private static final int STYLE_TRIANGLE = 1;
|
||||
private static final int STYLE_BLOCK = 2;
|
||||
private int mIndicatorStyle = STYLE_NORMAL;
|
||||
|
||||
private float mTabPadding;
|
||||
private boolean mTabSpaceEqual;
|
||||
private float mTabWidth;
|
||||
|
||||
/** indicator */
|
||||
private int mIndicatorColor;
|
||||
private float mIndicatorHeight;
|
||||
private float mIndicatorWidth;
|
||||
private float mIndicatorCornerRadius;
|
||||
private float mIndicatorMarginLeft;
|
||||
private float mIndicatorMarginTop;
|
||||
private float mIndicatorMarginRight;
|
||||
private float mIndicatorMarginBottom;
|
||||
private int mIndicatorGravity;
|
||||
private boolean mIndicatorWidthEqualTitle;
|
||||
|
||||
/** underline */
|
||||
private int mUnderlineColor;
|
||||
private float mUnderlineHeight;
|
||||
private int mUnderlineGravity;
|
||||
|
||||
/** divider */
|
||||
private int mDividerColor;
|
||||
private float mDividerWidth;
|
||||
private float mDividerPadding;
|
||||
|
||||
/** title */
|
||||
private static final int TEXT_BOLD_NONE = 0;
|
||||
private static final int TEXT_BOLD_WHEN_SELECT = 1;
|
||||
private static final int TEXT_BOLD_BOTH = 2;
|
||||
private float mTextsize;
|
||||
private int mTextSelectColor;
|
||||
private int mTextUnselectColor;
|
||||
private int mTextBold;
|
||||
private boolean mTextAllCaps;
|
||||
|
||||
private int mLastScrollX;
|
||||
private int mHeight;
|
||||
private boolean mSnapOnTabClick;
|
||||
|
||||
public SlidingTabLayout(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public SlidingTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setFillViewport(true);//设置滚动视图是否可以伸缩其内容以填充视口
|
||||
setWillNotDraw(false);//重写onDraw方法,需要调用这个方法来清除flag
|
||||
setClipChildren(false);
|
||||
setClipToPadding(false);
|
||||
|
||||
this.mContext = context;
|
||||
mTabsContainer = new LinearLayout(context);
|
||||
addView(mTabsContainer);
|
||||
|
||||
obtainAttributes(context, attrs);
|
||||
|
||||
//get layout_height
|
||||
String height = attrs.getAttributeValue("http://schemas.android.com/apk/res/android", "layout_height");
|
||||
|
||||
if (height.equals(ViewGroup.LayoutParams.MATCH_PARENT + "")) {
|
||||
} else if (height.equals(ViewGroup.LayoutParams.WRAP_CONTENT + "")) {
|
||||
} else {
|
||||
int[] systemAttrs = {android.R.attr.layout_height};
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, systemAttrs);
|
||||
mHeight = a.getDimensionPixelSize(0, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private void obtainAttributes(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabLayout);
|
||||
|
||||
mIndicatorStyle = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_style, STYLE_NORMAL);
|
||||
mIndicatorColor = ta.getColor(R.styleable.SlidingTabLayout_tl_indicator_color, Color.parseColor(mIndicatorStyle == STYLE_BLOCK ? "#4B6A87" : "#ffffff"));
|
||||
mIndicatorHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_height,
|
||||
dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 4 : (mIndicatorStyle == STYLE_BLOCK ? -1 : 2)));
|
||||
mIndicatorWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_width, dp2px(mIndicatorStyle == STYLE_TRIANGLE ? 10 : -1));
|
||||
mIndicatorCornerRadius = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_corner_radius, dp2px(mIndicatorStyle == STYLE_BLOCK ? -1 : 0));
|
||||
mIndicatorMarginLeft = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_left, dp2px(0));
|
||||
mIndicatorMarginTop = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_top, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorMarginRight = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_right, dp2px(0));
|
||||
mIndicatorMarginBottom = ta.getDimension(R.styleable.SlidingTabLayout_tl_indicator_margin_bottom, dp2px(mIndicatorStyle == STYLE_BLOCK ? 7 : 0));
|
||||
mIndicatorGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_indicator_gravity, Gravity.BOTTOM);
|
||||
mIndicatorWidthEqualTitle = ta.getBoolean(R.styleable.SlidingTabLayout_tl_indicator_width_equal_title, false);
|
||||
|
||||
mUnderlineColor = ta.getColor(R.styleable.SlidingTabLayout_tl_underline_color, Color.parseColor("#ffffff"));
|
||||
mUnderlineHeight = ta.getDimension(R.styleable.SlidingTabLayout_tl_underline_height, dp2px(0));
|
||||
mUnderlineGravity = ta.getInt(R.styleable.SlidingTabLayout_tl_underline_gravity, Gravity.BOTTOM);
|
||||
|
||||
mDividerColor = ta.getColor(R.styleable.SlidingTabLayout_tl_divider_color, Color.parseColor("#ffffff"));
|
||||
mDividerWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_width, dp2px(0));
|
||||
mDividerPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_divider_padding, dp2px(12));
|
||||
|
||||
mTextsize = ta.getDimension(R.styleable.SlidingTabLayout_tl_textsize, sp2px(14));
|
||||
mTextSelectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textSelectColor, Color.parseColor("#ffffff"));
|
||||
mTextUnselectColor = ta.getColor(R.styleable.SlidingTabLayout_tl_textUnselectColor, Color.parseColor("#AAffffff"));
|
||||
mTextBold = ta.getInt(R.styleable.SlidingTabLayout_tl_textBold, TEXT_BOLD_NONE);
|
||||
mTextAllCaps = ta.getBoolean(R.styleable.SlidingTabLayout_tl_textAllCaps, false);
|
||||
|
||||
mTabSpaceEqual = ta.getBoolean(R.styleable.SlidingTabLayout_tl_tab_space_equal, false);
|
||||
mTabWidth = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_width, dp2px(-1));
|
||||
mTabPadding = ta.getDimension(R.styleable.SlidingTabLayout_tl_tab_padding, mTabSpaceEqual || mTabWidth > 0 ? dp2px(0) : dp2px(20));
|
||||
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
/** 关联ViewPager */
|
||||
public void setViewPager(ViewPager vp) {
|
||||
if (vp == null || vp.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/** 关联ViewPager,用于不想在ViewPager适配器中设置titles数据的情况 */
|
||||
public void setViewPager(ViewPager vp, String[] titles) {
|
||||
if (vp == null || vp.getAdapter() == null) {
|
||||
throw new IllegalStateException("ViewPager or ViewPager adapter can not be NULL !");
|
||||
}
|
||||
|
||||
if (titles == null || titles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be EMPTY !");
|
||||
}
|
||||
|
||||
if (titles.length != vp.getAdapter().getCount()) {
|
||||
throw new IllegalStateException("Titles length must be the same as the page count !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
mTitles = new ArrayList<>();
|
||||
Collections.addAll(mTitles, titles);
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/** 关联ViewPager,用于连适配器都不想自己实例化的情况 */
|
||||
public void setViewPager(ViewPager vp, String[] titles, FragmentActivity fa, ArrayList<Fragment> fragments) {
|
||||
if (vp == null) {
|
||||
throw new IllegalStateException("ViewPager can not be NULL !");
|
||||
}
|
||||
|
||||
if (titles == null || titles.length == 0) {
|
||||
throw new IllegalStateException("Titles can not be EMPTY !");
|
||||
}
|
||||
|
||||
this.mViewPager = vp;
|
||||
this.mViewPager.setAdapter(new InnerPagerAdapter(fa.getSupportFragmentManager(), fragments, titles));
|
||||
|
||||
this.mViewPager.removeOnPageChangeListener(this);
|
||||
this.mViewPager.addOnPageChangeListener(this);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/** 更新数据 */
|
||||
public void notifyDataSetChanged() {
|
||||
mTabsContainer.removeAllViews();
|
||||
this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size();
|
||||
View tabView;
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
tabView = View.inflate(mContext, R.layout.flyco_layout_tab, null);
|
||||
CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(i) : mTitles.get(i);
|
||||
addTab(i, pageTitle.toString(), tabView);
|
||||
}
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void addNewTab(String title) {
|
||||
View tabView = View.inflate(mContext, R.layout.flyco_layout_tab, null);
|
||||
if (mTitles != null) {
|
||||
mTitles.add(title);
|
||||
}
|
||||
|
||||
CharSequence pageTitle = mTitles == null ? mViewPager.getAdapter().getPageTitle(mTabCount) : mTitles.get(mTabCount);
|
||||
addTab(mTabCount, pageTitle.toString(), tabView);
|
||||
this.mTabCount = mTitles == null ? mViewPager.getAdapter().getCount() : mTitles.size();
|
||||
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
/** 创建并添加tab */
|
||||
private void addTab(final int position, String title, View tabView) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
if (tv_tab_title != null) {
|
||||
if (title != null) tv_tab_title.setText(title);
|
||||
}
|
||||
|
||||
tabView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = mTabsContainer.indexOfChild(v);
|
||||
if (position != -1) {
|
||||
if (mViewPager.getCurrentItem() != position) {
|
||||
if (mSnapOnTabClick) {
|
||||
mViewPager.setCurrentItem(position, false);
|
||||
} else {
|
||||
mViewPager.setCurrentItem(position);
|
||||
}
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onTabSelect(position);
|
||||
}
|
||||
} else {
|
||||
if (mListener != null) {
|
||||
mListener.onTabReselect(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/** 每一个Tab的布局参数 */
|
||||
LinearLayout.LayoutParams lp_tab = mTabSpaceEqual ?
|
||||
new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
|
||||
new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
if (mTabWidth > 0) {
|
||||
lp_tab = new LinearLayout.LayoutParams((int) mTabWidth, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
|
||||
mTabsContainer.addView(tabView, position, lp_tab);
|
||||
}
|
||||
|
||||
private void updateTabStyles() {
|
||||
for (int i = 0; i < mTabCount; i++) {
|
||||
View v = mTabsContainer.getChildAt(i);
|
||||
// v.setPadding((int) mTabPadding, v.getPaddingTop(), (int) mTabPadding, v.getPaddingBottom());
|
||||
TextView tv_tab_title = (TextView) v.findViewById(R.id.tv_tab_title);
|
||||
if (tv_tab_title != null) {
|
||||
tv_tab_title.setTextColor(i == mCurrentTab ? mTextSelectColor : mTextUnselectColor);
|
||||
tv_tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextsize);
|
||||
tv_tab_title.setPadding((int) mTabPadding, 0, (int) mTabPadding, 0);
|
||||
if (mTextAllCaps) {
|
||||
tv_tab_title.setText(tv_tab_title.getText().toString().toUpperCase());
|
||||
}
|
||||
|
||||
if (mTextBold == TEXT_BOLD_BOTH) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(true);
|
||||
} else if (mTextBold == TEXT_BOLD_NONE) {
|
||||
tv_tab_title.getPaint().setFakeBoldText(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
/**
|
||||
* position:当前View的位置
|
||||
* mCurrentPositionOffset:当前View的偏移量比例.[0,1)
|
||||
*/
|
||||
this.mCurrentTab = position;
|
||||
this.mCurrentPositionOffset = positionOffset;
|
||||
scrollToCurrentTab();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
updateTabSelection(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
/** HorizontalScrollView滚到当前tab,并且居中显示 */
|
||||
private void scrollToCurrentTab() {
|
||||
if (mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = (int) (mCurrentPositionOffset * mTabsContainer.getChildAt(mCurrentTab).getWidth());
|
||||
/**当前Tab的left+当前Tab的Width乘以positionOffset*/
|
||||
int newScrollX = mTabsContainer.getChildAt(mCurrentTab).getLeft() + offset;
|
||||
|
||||
if (mCurrentTab > 0 || offset > 0) {
|
||||
/**HorizontalScrollView移动到当前tab,并居中*/
|
||||
newScrollX -= getWidth() / 2 - getPaddingLeft();
|
||||
calcIndicatorRect();
|
||||
newScrollX += ((mTabRect.right - mTabRect.left) / 2);
|
||||
}
|
||||
|
||||
if (newScrollX != mLastScrollX) {
|
||||
mLastScrollX = newScrollX;
|
||||
/** scrollTo(int x,int y):x,y代表的不是坐标点,而是偏移量
|
||||
* x:表示离起始位置的x水平方向的偏移量
|
||||
* y:表示离起始位置的y垂直方向的偏移量
|
||||
*/
|
||||
scrollTo(newScrollX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTabSelection(int position) {
|
||||
for (int i = 0; i < mTabCount; ++i) {
|
||||
View tabView = mTabsContainer.getChildAt(i);
|
||||
final boolean isSelect = i == position;
|
||||
TextView tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
|
||||
if (tab_title != null) {
|
||||
tab_title.setTextColor(isSelect ? mTextSelectColor : mTextUnselectColor);
|
||||
if (mTextBold == TEXT_BOLD_WHEN_SELECT) {
|
||||
tab_title.getPaint().setFakeBoldText(isSelect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float margin;
|
||||
|
||||
private void calcIndicatorRect() {
|
||||
View currentTabView = mTabsContainer.getChildAt(this.mCurrentTab);
|
||||
float left = currentTabView.getLeft();
|
||||
float right = currentTabView.getRight();
|
||||
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
TextView tab_title = (TextView) currentTabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float textWidth = mTextPaint.measureText(tab_title.getText().toString());
|
||||
margin = (right - left - textWidth) / 2;
|
||||
}
|
||||
|
||||
if (this.mCurrentTab < mTabCount - 1) {
|
||||
View nextTabView = mTabsContainer.getChildAt(this.mCurrentTab + 1);
|
||||
float nextTabLeft = nextTabView.getLeft();
|
||||
float nextTabRight = nextTabView.getRight();
|
||||
|
||||
left = left + mCurrentPositionOffset * (nextTabLeft - left);
|
||||
right = right + mCurrentPositionOffset * (nextTabRight - right);
|
||||
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
TextView next_tab_title = (TextView) nextTabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float nextTextWidth = mTextPaint.measureText(next_tab_title.getText().toString());
|
||||
float nextMargin = (nextTabRight - nextTabLeft - nextTextWidth) / 2;
|
||||
margin = margin + mCurrentPositionOffset * (nextMargin - margin);
|
||||
}
|
||||
}
|
||||
|
||||
mIndicatorRect.left = (int) left;
|
||||
mIndicatorRect.right = (int) right;
|
||||
//for mIndicatorWidthEqualTitle
|
||||
if (mIndicatorStyle == STYLE_NORMAL && mIndicatorWidthEqualTitle) {
|
||||
mIndicatorRect.left = (int) (left + margin - 1);
|
||||
mIndicatorRect.right = (int) (right - margin - 1);
|
||||
}
|
||||
|
||||
mTabRect.left = (int) left;
|
||||
mTabRect.right = (int) right;
|
||||
|
||||
if (mIndicatorWidth < 0) { //indicatorWidth小于0时,原jpardogo's PagerSlidingTabStrip
|
||||
|
||||
} else {//indicatorWidth大于0时,圆角矩形以及三角形
|
||||
float indicatorLeft = currentTabView.getLeft() + (currentTabView.getWidth() - mIndicatorWidth) / 2;
|
||||
|
||||
if (this.mCurrentTab < mTabCount - 1) {
|
||||
View nextTab = mTabsContainer.getChildAt(this.mCurrentTab + 1);
|
||||
indicatorLeft = indicatorLeft + mCurrentPositionOffset * (currentTabView.getWidth() / 2 + nextTab.getWidth() / 2);
|
||||
}
|
||||
|
||||
mIndicatorRect.left = (int) indicatorLeft;
|
||||
mIndicatorRect.right = (int) (mIndicatorRect.left + mIndicatorWidth);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (isInEditMode() || mTabCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int height = getHeight();
|
||||
int paddingLeft = getPaddingLeft();
|
||||
// draw divider
|
||||
if (mDividerWidth > 0) {
|
||||
mDividerPaint.setStrokeWidth(mDividerWidth);
|
||||
mDividerPaint.setColor(mDividerColor);
|
||||
for (int i = 0; i < mTabCount - 1; i++) {
|
||||
View tab = mTabsContainer.getChildAt(i);
|
||||
canvas.drawLine(paddingLeft + tab.getRight(), mDividerPadding, paddingLeft + tab.getRight(), height - mDividerPadding, mDividerPaint);
|
||||
}
|
||||
}
|
||||
|
||||
// draw underline
|
||||
if (mUnderlineHeight > 0) {
|
||||
mRectPaint.setColor(mUnderlineColor);
|
||||
if (mUnderlineGravity == Gravity.BOTTOM) {
|
||||
canvas.drawRect(paddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + paddingLeft, height, mRectPaint);
|
||||
} else {
|
||||
canvas.drawRect(paddingLeft, 0, mTabsContainer.getWidth() + paddingLeft, mUnderlineHeight, mRectPaint);
|
||||
}
|
||||
}
|
||||
|
||||
//draw indicator line
|
||||
|
||||
calcIndicatorRect();
|
||||
if (mIndicatorStyle == STYLE_TRIANGLE) {
|
||||
if (mIndicatorHeight > 0) {
|
||||
mTrianglePaint.setColor(mIndicatorColor);
|
||||
mTrianglePath.reset();
|
||||
mTrianglePath.moveTo(paddingLeft + mIndicatorRect.left, height);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.left / 2 + mIndicatorRect.right / 2, height - mIndicatorHeight);
|
||||
mTrianglePath.lineTo(paddingLeft + mIndicatorRect.right, height);
|
||||
mTrianglePath.close();
|
||||
canvas.drawPath(mTrianglePath, mTrianglePaint);
|
||||
}
|
||||
} else if (mIndicatorStyle == STYLE_BLOCK) {
|
||||
if (mIndicatorHeight < 0) {
|
||||
mIndicatorHeight = height - mIndicatorMarginTop - mIndicatorMarginBottom;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
if (mIndicatorCornerRadius < 0 || mIndicatorCornerRadius > mIndicatorHeight / 2) {
|
||||
mIndicatorCornerRadius = mIndicatorHeight / 2;
|
||||
}
|
||||
|
||||
mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop, (int) (paddingLeft + mIndicatorRect.right - mIndicatorMarginRight),
|
||||
(int) (mIndicatorMarginTop + mIndicatorHeight));
|
||||
mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
}
|
||||
} else {
|
||||
/* mRectPaint.setColor(mIndicatorColor);
|
||||
calcIndicatorRect();
|
||||
canvas.drawRect(getPaddingLeft() + mIndicatorRect.left, getHeight() - mIndicatorHeight,
|
||||
mIndicatorRect.right + getPaddingLeft(), getHeight(), mRectPaint);*/
|
||||
|
||||
if (mIndicatorHeight > 0) {
|
||||
mIndicatorDrawable.setColor(mIndicatorColor);
|
||||
|
||||
if (mIndicatorGravity == Gravity.BOTTOM) {
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
height - (int) mIndicatorHeight - (int) mIndicatorMarginBottom,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
height - (int) mIndicatorMarginBottom);
|
||||
} else {
|
||||
mIndicatorDrawable.setBounds(paddingLeft + (int) mIndicatorMarginLeft + mIndicatorRect.left,
|
||||
(int) mIndicatorMarginTop,
|
||||
paddingLeft + mIndicatorRect.right - (int) mIndicatorMarginRight,
|
||||
(int) mIndicatorHeight + (int) mIndicatorMarginTop);
|
||||
}
|
||||
mIndicatorDrawable.setCornerRadius(mIndicatorCornerRadius);
|
||||
mIndicatorDrawable.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
public void setCurrentTab(int currentTab) {
|
||||
this.mCurrentTab = currentTab;
|
||||
mViewPager.setCurrentItem(currentTab);
|
||||
|
||||
}
|
||||
|
||||
public void setCurrentTab(int currentTab, boolean smoothScroll) {
|
||||
this.mCurrentTab = currentTab;
|
||||
mViewPager.setCurrentItem(currentTab, smoothScroll);
|
||||
}
|
||||
|
||||
public void setIndicatorStyle(int indicatorStyle) {
|
||||
this.mIndicatorStyle = indicatorStyle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTabPadding(float tabPadding) {
|
||||
this.mTabPadding = dp2px(tabPadding);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabSpaceEqual(boolean tabSpaceEqual) {
|
||||
this.mTabSpaceEqual = tabSpaceEqual;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTabWidth(float tabWidth) {
|
||||
this.mTabWidth = dp2px(tabWidth);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int indicatorColor) {
|
||||
this.mIndicatorColor = indicatorColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorHeight(float indicatorHeight) {
|
||||
this.mIndicatorHeight = dp2px(indicatorHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidth(float indicatorWidth) {
|
||||
this.mIndicatorWidth = dp2px(indicatorWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorCornerRadius(float indicatorCornerRadius) {
|
||||
this.mIndicatorCornerRadius = dp2px(indicatorCornerRadius);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorGravity(int indicatorGravity) {
|
||||
this.mIndicatorGravity = indicatorGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorMargin(float indicatorMarginLeft, float indicatorMarginTop,
|
||||
float indicatorMarginRight, float indicatorMarginBottom) {
|
||||
this.mIndicatorMarginLeft = dp2px(indicatorMarginLeft);
|
||||
this.mIndicatorMarginTop = dp2px(indicatorMarginTop);
|
||||
this.mIndicatorMarginRight = dp2px(indicatorMarginRight);
|
||||
this.mIndicatorMarginBottom = dp2px(indicatorMarginBottom);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setIndicatorWidthEqualTitle(boolean indicatorWidthEqualTitle) {
|
||||
this.mIndicatorWidthEqualTitle = indicatorWidthEqualTitle;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineColor(int underlineColor) {
|
||||
this.mUnderlineColor = underlineColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineHeight(float underlineHeight) {
|
||||
this.mUnderlineHeight = dp2px(underlineHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setUnderlineGravity(int underlineGravity) {
|
||||
this.mUnderlineGravity = underlineGravity;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerColor(int dividerColor) {
|
||||
this.mDividerColor = dividerColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerWidth(float dividerWidth) {
|
||||
this.mDividerWidth = dp2px(dividerWidth);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDividerPadding(float dividerPadding) {
|
||||
this.mDividerPadding = dp2px(dividerPadding);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setTextsize(float textsize) {
|
||||
this.mTextsize = sp2px(textsize);
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextSelectColor(int textSelectColor) {
|
||||
this.mTextSelectColor = textSelectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextUnselectColor(int textUnselectColor) {
|
||||
this.mTextUnselectColor = textUnselectColor;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextBold(int textBold) {
|
||||
this.mTextBold = textBold;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setTextAllCaps(boolean textAllCaps) {
|
||||
this.mTextAllCaps = textAllCaps;
|
||||
updateTabStyles();
|
||||
}
|
||||
|
||||
public void setSnapOnTabClick(boolean snapOnTabClick) {
|
||||
mSnapOnTabClick = snapOnTabClick;
|
||||
}
|
||||
|
||||
|
||||
public int getTabCount() {
|
||||
return mTabCount;
|
||||
}
|
||||
|
||||
public int getCurrentTab() {
|
||||
return mCurrentTab;
|
||||
}
|
||||
|
||||
public int getIndicatorStyle() {
|
||||
return mIndicatorStyle;
|
||||
}
|
||||
|
||||
public float getTabPadding() {
|
||||
return mTabPadding;
|
||||
}
|
||||
|
||||
public boolean isTabSpaceEqual() {
|
||||
return mTabSpaceEqual;
|
||||
}
|
||||
|
||||
public float getTabWidth() {
|
||||
return mTabWidth;
|
||||
}
|
||||
|
||||
public int getIndicatorColor() {
|
||||
return mIndicatorColor;
|
||||
}
|
||||
|
||||
public float getIndicatorHeight() {
|
||||
return mIndicatorHeight;
|
||||
}
|
||||
|
||||
public float getIndicatorWidth() {
|
||||
return mIndicatorWidth;
|
||||
}
|
||||
|
||||
public float getIndicatorCornerRadius() {
|
||||
return mIndicatorCornerRadius;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginLeft() {
|
||||
return mIndicatorMarginLeft;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginTop() {
|
||||
return mIndicatorMarginTop;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginRight() {
|
||||
return mIndicatorMarginRight;
|
||||
}
|
||||
|
||||
public float getIndicatorMarginBottom() {
|
||||
return mIndicatorMarginBottom;
|
||||
}
|
||||
|
||||
public int getUnderlineColor() {
|
||||
return mUnderlineColor;
|
||||
}
|
||||
|
||||
public float getUnderlineHeight() {
|
||||
return mUnderlineHeight;
|
||||
}
|
||||
|
||||
public int getDividerColor() {
|
||||
return mDividerColor;
|
||||
}
|
||||
|
||||
public float getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
public float getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
public float getTextsize() {
|
||||
return mTextsize;
|
||||
}
|
||||
|
||||
public int getTextSelectColor() {
|
||||
return mTextSelectColor;
|
||||
}
|
||||
|
||||
public int getTextUnselectColor() {
|
||||
return mTextUnselectColor;
|
||||
}
|
||||
|
||||
public int getTextBold() {
|
||||
return mTextBold;
|
||||
}
|
||||
|
||||
public boolean isTextAllCaps() {
|
||||
return mTextAllCaps;
|
||||
}
|
||||
|
||||
public TextView getTitleView(int tab) {
|
||||
View tabView = mTabsContainer.getChildAt(tab);
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
return tv_tab_title;
|
||||
}
|
||||
|
||||
//setter and getter
|
||||
|
||||
// show MsgTipView
|
||||
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private SparseArray<Boolean> mInitSetMap = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* 显示未读消息
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
* @param num num小于等于0显示红点,num大于0显示数字
|
||||
*/
|
||||
public void showMsg(int position, int num) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
UnreadMsgUtils.show(tipView, num);
|
||||
|
||||
if (mInitSetMap.get(position) != null && mInitSetMap.get(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setMsgMargin(position, 4, 2);
|
||||
mInitSetMap.put(position, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示未读红点
|
||||
*
|
||||
* @param position 显示tab位置
|
||||
*/
|
||||
public void showDot(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
showMsg(position, 0);
|
||||
}
|
||||
|
||||
/** 隐藏未读消息 */
|
||||
public void hideMsg(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
tipView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/** 设置未读消息偏移,原点为文字的右上角.当控件高度固定,消息提示位置易控制,显示效果佳 */
|
||||
public void setMsgMargin(int position, float leftPadding, float bottomPadding) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
if (tipView != null) {
|
||||
TextView tv_tab_title = (TextView) tabView.findViewById(R.id.tv_tab_title);
|
||||
mTextPaint.setTextSize(mTextsize);
|
||||
float textWidth = mTextPaint.measureText(tv_tab_title.getText().toString());
|
||||
float textHeight = mTextPaint.descent() - mTextPaint.ascent();
|
||||
MarginLayoutParams lp = (MarginLayoutParams) tipView.getLayoutParams();
|
||||
lp.leftMargin = mTabWidth >= 0 ? (int) (mTabWidth / 2 + textWidth / 2 + dp2px(leftPadding)) : (int) (mTabPadding + textWidth + dp2px(leftPadding));
|
||||
lp.topMargin = mHeight > 0 ? (int) (mHeight - textHeight) / 2 - dp2px(bottomPadding) : 0;
|
||||
tipView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前类只提供了少许设置未读消息属性的方法,可以通过该方法获取MsgView对象从而各种设置 */
|
||||
public MsgView getMsgView(int position) {
|
||||
if (position >= mTabCount) {
|
||||
position = mTabCount - 1;
|
||||
}
|
||||
View tabView = mTabsContainer.getChildAt(position);
|
||||
MsgView tipView = (MsgView) tabView.findViewById(R.id.rtv_msg_tip);
|
||||
return tipView;
|
||||
}
|
||||
|
||||
private OnTabSelectListener mListener;
|
||||
|
||||
public void setOnTabSelectListener(OnTabSelectListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
class InnerPagerAdapter extends FragmentPagerAdapter {
|
||||
private ArrayList<Fragment> fragments = new ArrayList<>();
|
||||
private String[] titles;
|
||||
|
||||
public InnerPagerAdapter(FragmentManager fm, ArrayList<Fragment> fragments, String[] titles) {
|
||||
super(fm);
|
||||
this.fragments = fragments;
|
||||
this.titles = titles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return fragments.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return titles[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return fragments.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
// 覆写destroyItem并且空实现,这样每个Fragment中的视图就不会被销毁
|
||||
// super.destroyItem(container, position, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(Object object) {
|
||||
return PagerAdapter.POSITION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable("instanceState", super.onSaveInstanceState());
|
||||
bundle.putInt("mCurrentTab", mCurrentTab);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
Bundle bundle = (Bundle) state;
|
||||
mCurrentTab = bundle.getInt("mCurrentTab");
|
||||
state = bundle.getParcelable("instanceState");
|
||||
if (mCurrentTab != 0 && mTabsContainer.getChildCount() > 0) {
|
||||
updateTabSelection(mCurrentTab);
|
||||
scrollToCurrentTab();
|
||||
}
|
||||
}
|
||||
super.onRestoreInstanceState(state);
|
||||
}
|
||||
|
||||
protected int dp2px(float dp) {
|
||||
final float scale = mContext.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
protected int sp2px(float sp) {
|
||||
final float scale = this.mContext.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (sp * scale + 0.5f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.example.moduletablayout.listener;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
public interface CustomTabEntity {
|
||||
String getTabTitle();
|
||||
|
||||
@DrawableRes
|
||||
int getTabSelectedIcon();
|
||||
|
||||
@DrawableRes
|
||||
int getTabUnselectedIcon();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.example.moduletablayout.listener;
|
||||
|
||||
public interface OnTabSelectListener {
|
||||
void onTabSelect(int position);
|
||||
void onTabReselect(int position);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.example.moduletablayout.utils;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class FragmentChangeManager {
|
||||
private FragmentManager mFragmentManager;
|
||||
private int mContainerViewId;
|
||||
/** Fragment切换数组 */
|
||||
private ArrayList<Fragment> mFragments;
|
||||
/** 当前选中的Tab */
|
||||
private int mCurrentTab;
|
||||
|
||||
public FragmentChangeManager(FragmentManager fm, int containerViewId, ArrayList<Fragment> fragments) {
|
||||
this.mFragmentManager = fm;
|
||||
this.mContainerViewId = containerViewId;
|
||||
this.mFragments = fragments;
|
||||
initFragments();
|
||||
}
|
||||
|
||||
/** 初始化fragments */
|
||||
private void initFragments() {
|
||||
for (Fragment fragment : mFragments) {
|
||||
mFragmentManager.beginTransaction().add(mContainerViewId, fragment).hide(fragment).commit();
|
||||
}
|
||||
|
||||
setFragments(0);
|
||||
}
|
||||
|
||||
/** 界面切换控制 */
|
||||
public void setFragments(int index) {
|
||||
for (int i = 0; i < mFragments.size(); i++) {
|
||||
FragmentTransaction ft = mFragmentManager.beginTransaction();
|
||||
Fragment fragment = mFragments.get(i);
|
||||
if (i == index) {
|
||||
ft.show(fragment);
|
||||
} else {
|
||||
ft.hide(fragment);
|
||||
}
|
||||
ft.commit();
|
||||
}
|
||||
mCurrentTab = index;
|
||||
}
|
||||
|
||||
public int getCurrentTab() {
|
||||
return mCurrentTab;
|
||||
}
|
||||
|
||||
public Fragment getCurrentFragment() {
|
||||
return mFragments.get(mCurrentTab);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.example.moduletablayout.utils;
|
||||
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.example.moduletablayout.widget.MsgView;
|
||||
|
||||
|
||||
/**
|
||||
* 未读消息提示View,显示小红点或者带有数字的红点:
|
||||
* 数字一位,圆
|
||||
* 数字两位,圆角矩形,圆角是高度的一半
|
||||
* 数字超过两位,显示99+
|
||||
*/
|
||||
public class UnreadMsgUtils {
|
||||
public static void show(MsgView msgView, int num) {
|
||||
if (msgView == null) {
|
||||
return;
|
||||
}
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) msgView.getLayoutParams();
|
||||
DisplayMetrics dm = msgView.getResources().getDisplayMetrics();
|
||||
msgView.setVisibility(View.VISIBLE);
|
||||
if (num <= 0) {//圆点,设置默认宽高
|
||||
msgView.setStrokeWidth(0);
|
||||
msgView.setText("");
|
||||
|
||||
lp.width = (int) (5 * dm.density);
|
||||
lp.height = (int) (5 * dm.density);
|
||||
msgView.setLayoutParams(lp);
|
||||
} else {
|
||||
lp.height = (int) (18 * dm.density);
|
||||
if (num > 0 && num < 10) {//圆
|
||||
lp.width = (int) (18 * dm.density);
|
||||
msgView.setText(num + "");
|
||||
} else if (num > 9 && num < 100) {//圆角矩形,圆角是高度的一半,设置默认padding
|
||||
lp.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
|
||||
msgView.setPadding((int) (6 * dm.density), 0, (int) (6 * dm.density), 0);
|
||||
msgView.setText(num + "");
|
||||
} else {//数字超过两位,显示99+
|
||||
lp.width = RelativeLayout.LayoutParams.WRAP_CONTENT;
|
||||
msgView.setPadding((int) (6 * dm.density), 0, (int) (6 * dm.density), 0);
|
||||
msgView.setText("99+");
|
||||
}
|
||||
msgView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setSize(MsgView rtv, int size) {
|
||||
if (rtv == null) {
|
||||
return;
|
||||
}
|
||||
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) rtv.getLayoutParams();
|
||||
lp.width = size;
|
||||
lp.height = size;
|
||||
rtv.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.example.moduletablayout.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.StateListDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.example.moduletablayout.R;
|
||||
|
||||
|
||||
/** 用于需要圆角矩形框背景的TextView的情况,减少直接使用TextView时引入的shape资源文件 */
|
||||
public class MsgView extends TextView {
|
||||
private Context context;
|
||||
private GradientDrawable gd_background = new GradientDrawable();
|
||||
private int backgroundColor;
|
||||
private int cornerRadius;
|
||||
private int strokeWidth;
|
||||
private int strokeColor;
|
||||
private boolean isRadiusHalfHeight;
|
||||
private boolean isWidthHeightEqual;
|
||||
|
||||
public MsgView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public MsgView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public MsgView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
this.context = context;
|
||||
obtainAttributes(context, attrs);
|
||||
}
|
||||
|
||||
private void obtainAttributes(Context context, AttributeSet attrs) {
|
||||
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MsgView);
|
||||
backgroundColor = ta.getColor(R.styleable.MsgView_mv_backgroundColor, Color.TRANSPARENT);
|
||||
cornerRadius = ta.getDimensionPixelSize(R.styleable.MsgView_mv_cornerRadius, 0);
|
||||
strokeWidth = ta.getDimensionPixelSize(R.styleable.MsgView_mv_strokeWidth, 0);
|
||||
strokeColor = ta.getColor(R.styleable.MsgView_mv_strokeColor, Color.TRANSPARENT);
|
||||
isRadiusHalfHeight = ta.getBoolean(R.styleable.MsgView_mv_isRadiusHalfHeight, false);
|
||||
isWidthHeightEqual = ta.getBoolean(R.styleable.MsgView_mv_isWidthHeightEqual, false);
|
||||
|
||||
ta.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (isWidthHeightEqual() && getWidth() > 0 && getHeight() > 0) {
|
||||
int max = Math.max(getWidth(), getHeight());
|
||||
int measureSpec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
|
||||
super.onMeasure(measureSpec, measureSpec);
|
||||
return;
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (isRadiusHalfHeight()) {
|
||||
setCornerRadius(getHeight() / 2);
|
||||
} else {
|
||||
setBgSelector();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setBackgroundColor(int backgroundColor) {
|
||||
this.backgroundColor = backgroundColor;
|
||||
setBgSelector();
|
||||
}
|
||||
|
||||
public void setCornerRadius(int cornerRadius) {
|
||||
this.cornerRadius = dp2px(cornerRadius);
|
||||
setBgSelector();
|
||||
}
|
||||
|
||||
public void setStrokeWidth(int strokeWidth) {
|
||||
this.strokeWidth = dp2px(strokeWidth);
|
||||
setBgSelector();
|
||||
}
|
||||
|
||||
public void setStrokeColor(int strokeColor) {
|
||||
this.strokeColor = strokeColor;
|
||||
setBgSelector();
|
||||
}
|
||||
|
||||
public void setIsRadiusHalfHeight(boolean isRadiusHalfHeight) {
|
||||
this.isRadiusHalfHeight = isRadiusHalfHeight;
|
||||
setBgSelector();
|
||||
}
|
||||
|
||||
public void setIsWidthHeightEqual(boolean isWidthHeightEqual) {
|
||||
this.isWidthHeightEqual = isWidthHeightEqual;
|
||||
setBgSelector();
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
public int getCornerRadius() {
|
||||
return cornerRadius;
|
||||
}
|
||||
|
||||
public int getStrokeWidth() {
|
||||
return strokeWidth;
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return strokeColor;
|
||||
}
|
||||
|
||||
public boolean isRadiusHalfHeight() {
|
||||
return isRadiusHalfHeight;
|
||||
}
|
||||
|
||||
public boolean isWidthHeightEqual() {
|
||||
return isWidthHeightEqual;
|
||||
}
|
||||
|
||||
protected int dp2px(float dp) {
|
||||
final float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
|
||||
protected int sp2px(float sp) {
|
||||
final float scale = this.context.getResources().getDisplayMetrics().scaledDensity;
|
||||
return (int) (sp * scale + 0.5f);
|
||||
}
|
||||
|
||||
private void setDrawable(GradientDrawable gd, int color, int strokeColor) {
|
||||
gd.setColor(color);
|
||||
gd.setCornerRadius(cornerRadius);
|
||||
gd.setStroke(strokeWidth, strokeColor);
|
||||
}
|
||||
|
||||
public void setBgSelector() {
|
||||
StateListDrawable bg = new StateListDrawable();
|
||||
|
||||
setDrawable(gd_background, backgroundColor, strokeColor);
|
||||
bg.addState(new int[]{-android.R.attr.state_pressed}, gd_background);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {//16
|
||||
setBackground(bg);
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
setBackgroundDrawable(bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.example.moduletablayout.widget;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Author: wangjie
|
||||
* Email: tiantian.china.2@gmail.com
|
||||
* Date: 5/25/15.
|
||||
*/
|
||||
public class ShadowProperty implements Serializable {
|
||||
public static final int ALL = 0x1111;
|
||||
public static final int LEFT = 0x0001;
|
||||
public static final int TOP = 0x0010;
|
||||
public static final int RIGHT = 0x0100;
|
||||
public static final int BOTTOM = 0x1000;
|
||||
|
||||
/**
|
||||
* 阴影颜色
|
||||
*/
|
||||
private int shadowColor;
|
||||
/**
|
||||
* 阴影半径
|
||||
*/
|
||||
private int shadowRadius;
|
||||
/**
|
||||
* 阴影x偏移
|
||||
*/
|
||||
private int shadowDx;
|
||||
/**
|
||||
* 阴影y偏移
|
||||
*/
|
||||
private int shadowDy;
|
||||
|
||||
/**
|
||||
* 阴影边
|
||||
*/
|
||||
private int shadowSide = ALL;
|
||||
|
||||
public int getShadowSide() {
|
||||
return shadowSide;
|
||||
}
|
||||
|
||||
public ShadowProperty setShadowSide(int shadowSide) {
|
||||
this.shadowSide = shadowSide;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getShadowOffset() {
|
||||
return getShadowOffsetHalf() * 2;
|
||||
}
|
||||
|
||||
public int getShadowOffsetHalf() {
|
||||
return 0 >= shadowRadius ? 0 : Math.max(shadowDx, shadowDy) + shadowRadius;
|
||||
}
|
||||
|
||||
public int getShadowColor() {
|
||||
return shadowColor;
|
||||
}
|
||||
|
||||
public ShadowProperty setShadowColor(int shadowColor) {
|
||||
this.shadowColor = shadowColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getShadowRadius() {
|
||||
return shadowRadius;
|
||||
}
|
||||
|
||||
public ShadowProperty setShadowRadius(int shadowRadius) {
|
||||
this.shadowRadius = shadowRadius;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getShadowDx() {
|
||||
return shadowDx;
|
||||
}
|
||||
|
||||
public ShadowProperty setShadowDx(int shadowDx) {
|
||||
this.shadowDx = shadowDx;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getShadowDy() {
|
||||
return shadowDy;
|
||||
}
|
||||
|
||||
public ShadowProperty setShadowDy(int shadowDy) {
|
||||
this.shadowDy = shadowDy;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.example.moduletablayout.widget;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) {
|
||||
* view.setLayerType(View.LAYER_TYPE_SOFTWARE, drawable.getPaint());
|
||||
* }
|
||||
* </code>
|
||||
* <p/>
|
||||
* Author: wangjie
|
||||
* Email: tiantian.china.2@gmail.com
|
||||
* Date: 5/2/15.
|
||||
*/
|
||||
public class ShadowViewDrawable extends Drawable {
|
||||
private Paint paint;
|
||||
|
||||
private RectF bounds = new RectF();
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
private ShadowProperty shadowProperty;
|
||||
private int shadowOffset;
|
||||
|
||||
private RectF drawRect;
|
||||
|
||||
private float rx;
|
||||
private float ry;
|
||||
|
||||
public ShadowViewDrawable(ShadowProperty shadowProperty, int color, float rx, float ry) {
|
||||
this.shadowProperty = shadowProperty;
|
||||
shadowOffset = this.shadowProperty.getShadowOffset();
|
||||
|
||||
this.rx = rx;
|
||||
this.ry = ry;
|
||||
|
||||
paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
/**
|
||||
* 解决旋转时的锯齿问题
|
||||
*/
|
||||
paint.setFilterBitmap(true);
|
||||
paint.setDither(true);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
paint.setColor(color);
|
||||
/**
|
||||
* 设置阴影
|
||||
*/
|
||||
paint.setShadowLayer(shadowProperty.getShadowRadius(), shadowProperty.getShadowDx(), shadowProperty.getShadowDy(), shadowProperty.getShadowColor());
|
||||
|
||||
drawRect = new RectF();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
if (bounds.right - bounds.left > 0 && bounds.bottom - bounds.top > 0) {
|
||||
this.bounds.left = bounds.left;
|
||||
this.bounds.right = bounds.right;
|
||||
this.bounds.top = bounds.top;
|
||||
this.bounds.bottom = bounds.bottom;
|
||||
width = (int) (this.bounds.right - this.bounds.left);
|
||||
height = (int) (this.bounds.bottom - this.bounds.top);
|
||||
|
||||
// drawRect = new RectF(shadowOffset, shadowOffset, width - shadowOffset, height - shadowOffset);
|
||||
// drawRect = new RectF(0, 0, width, height - shadowOffset);
|
||||
|
||||
int shadowSide = shadowProperty.getShadowSide();
|
||||
int left = (shadowSide & ShadowProperty.LEFT) == ShadowProperty.LEFT ? shadowOffset : 0;
|
||||
int top = (shadowSide & ShadowProperty.TOP) == ShadowProperty.TOP ? shadowOffset : 0;
|
||||
int right = width - ((shadowSide & ShadowProperty.RIGHT) == ShadowProperty.RIGHT ? shadowOffset : 0);
|
||||
int bottom = height - ((shadowSide & ShadowProperty.BOTTOM) == ShadowProperty.BOTTOM ? shadowOffset : 0);
|
||||
|
||||
drawRect = new RectF(left, top, right, bottom);
|
||||
|
||||
|
||||
invalidateSelf();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private PorterDuffXfermode srcOut = new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT);
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
paint.setXfermode(null);
|
||||
|
||||
canvas.drawRoundRect(
|
||||
drawRect,
|
||||
rx, ry,
|
||||
paint
|
||||
);
|
||||
|
||||
paint.setXfermode(srcOut);
|
||||
// paint.setColor(Color.TRANSPARENT);
|
||||
canvas.drawRoundRect(drawRect, rx, ry, paint);
|
||||
}
|
||||
|
||||
public ShadowViewDrawable setColor(int color) {
|
||||
paint.setColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.UNKNOWN;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 130 B |
BIN
moduletablayout/src/main/res/drawable-xxhdpi/tab_x.png
Normal file
BIN
moduletablayout/src/main/res/drawable-xxhdpi/tab_x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
30
moduletablayout/src/main/res/layout/flyco_layout_tab.xml
Normal file
30
moduletablayout/src/main/res/layout/flyco_layout_tab.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
android:text="TAB" />
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
29
moduletablayout/src/main/res/layout/flyco_layout_tab_img.xml
Normal file
29
moduletablayout/src/main/res/layout/flyco_layout_tab_img.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:singleLine="true" />
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
45
moduletablayout/src/main/res/layout/layout_tab_bottom.xml
Normal file
45
moduletablayout/src/main/res/layout/layout_tab_bottom.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_tap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tab_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@+id/ll_tap"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
44
moduletablayout/src/main/res/layout/layout_tab_left.xml
Normal file
44
moduletablayout/src/main/res/layout/layout_tab_left.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_tap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tab_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView
|
||||
android:layout_toRightOf="@+id/ll_tap"
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
45
moduletablayout/src/main/res/layout/layout_tab_right.xml
Normal file
45
moduletablayout/src/main/res/layout/layout_tab_right.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_tap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tab_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@+id/ll_tap"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
39
moduletablayout/src/main/res/layout/layout_tab_segment.xml
Normal file
39
moduletablayout/src/main/res/layout/layout_tab_segment.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_tap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView
|
||||
android:layout_toRightOf="@+id/ll_tap"
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
44
moduletablayout/src/main/res/layout/layout_tab_top.xml
Normal file
44
moduletablayout/src/main/res/layout/layout_tab_top.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_tap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_tab_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_tab_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
|
||||
<com.example.moduletablayout.widget.MsgView
|
||||
android:id="@+id/rtv_msg_tip"
|
||||
xmlns:mv="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@+id/ll_tap"
|
||||
android:gravity="center"
|
||||
android:textColor="#ffffff"
|
||||
android:textSize="11.5sp"
|
||||
android:visibility="gone"
|
||||
mv:mv_backgroundColor="#FD481F"
|
||||
mv:mv_isRadiusHalfHeight="true"
|
||||
mv:mv_strokeColor="#ffffff"
|
||||
mv:mv_strokeWidth="1dp"/>
|
||||
|
||||
</RelativeLayout>
|
||||
269
moduletablayout/src/main/res/values/attrs.xml
Normal file
269
moduletablayout/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,269 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- indicator -->
|
||||
<!-- 设置显示器颜色 -->
|
||||
<attr name="tl_indicator_color" format="color"/>
|
||||
<!-- 设置显示器高度 -->
|
||||
<attr name="tl_indicator_height" format="dimension"/>
|
||||
<!-- 设置显示器固定宽度 -->
|
||||
<attr name="tl_indicator_width" format="dimension"/>
|
||||
<attr name="tl_indicator_drawable" format="reference" />
|
||||
<!-- 设置显示器margin,当indicator_width大于0,无效 -->
|
||||
<attr name="tl_indicator_margin_left" format="dimension"/>
|
||||
<attr name="tl_indicator_margin_top" format="dimension"/>
|
||||
<attr name="tl_indicator_margin_right" format="dimension"/>
|
||||
<attr name="tl_indicator_margin_bottom" format="dimension"/>
|
||||
<!-- 设置显示器圆角弧度-->
|
||||
<attr name="tl_indicator_corner_radius" format="dimension"/>
|
||||
<!-- 设置显示器上方还是下方,只对圆角矩形有用-->
|
||||
<attr name="tl_indicator_gravity" format="enum">
|
||||
<enum name="TOP" value="48"/>
|
||||
<enum name="BOTTOM" value="80"/>
|
||||
</attr>
|
||||
<!-- 设置显示器为常规|三角形|背景色块|-->
|
||||
<attr name="tl_indicator_style" format="enum">
|
||||
<enum name="NORMAL" value="0"/>
|
||||
<enum name="TRIANGLE" value="1"/>
|
||||
<enum name="BLOCK" value="2"/>
|
||||
</attr>
|
||||
<!-- 设置显示器长度与title一样长,只有在STYLE_NORMAL并且indicatorWidth小于零有效-->
|
||||
<attr name="tl_indicator_width_equal_title" format="boolean"/>
|
||||
<!-- 设置显示器支持动画-->
|
||||
<attr name="tl_indicator_anim_enable" format="boolean"/>
|
||||
<!-- 设置显示器动画时间-->
|
||||
<attr name="tl_indicator_anim_duration" format="integer"/>
|
||||
<!-- 设置显示器支持动画回弹效果-->
|
||||
<attr name="tl_indicator_bounce_enable" format="boolean"/>
|
||||
|
||||
<!-- underline -->
|
||||
<!-- 设置下划线颜色 -->
|
||||
<attr name="tl_underline_color" format="color"/>
|
||||
<!-- 设置下划线高度 -->
|
||||
<attr name="tl_underline_height" format="dimension"/>
|
||||
<!-- 设置下划线上方还是下方-->
|
||||
<attr name="tl_underline_gravity" format="enum">
|
||||
<enum name="TOP" value="48"/>
|
||||
<enum name="BOTTOM" value="80"/>
|
||||
</attr>
|
||||
|
||||
<!-- divider -->
|
||||
<!-- 设置分割线颜色 -->
|
||||
<attr name="tl_divider_color" format="color"/>
|
||||
<!-- 设置分割线宽度 -->
|
||||
<attr name="tl_divider_width" format="dimension"/>
|
||||
<!-- 设置分割线的paddingTop和paddingBottom -->
|
||||
<attr name="tl_divider_padding" format="dimension"/>
|
||||
|
||||
<!-- tab -->
|
||||
<!-- 设置tab的paddingLeft和paddingRight -->
|
||||
<attr name="tl_tab_padding" format="dimension"/>
|
||||
<!-- 设置tab大小等分 -->
|
||||
<attr name="tl_tab_space_equal" format="boolean"/>
|
||||
<!-- 设置tab固定大小 -->
|
||||
<attr name="tl_tab_width" format="dimension"/>
|
||||
|
||||
<!-- title -->
|
||||
<!-- 设置字体大小 -->
|
||||
<attr name="tl_textsize" format="dimension"/>
|
||||
<!-- 设置选择字体大小 -->
|
||||
<attr name="tl_textSelectedSize" format="dimension"/>
|
||||
<!-- 设置字体选中颜色 -->
|
||||
<attr name="tl_textSelectColor" format="color"/>
|
||||
<!-- 设置字体未选中颜色 -->
|
||||
<attr name="tl_textUnselectColor" format="color"/>
|
||||
<!-- 设置字体加粗 -->
|
||||
<attr name="tl_textBold" format="enum">
|
||||
<enum name="NONE" value="0"/>
|
||||
<enum name="SELECT" value="1"/>
|
||||
<enum name="BOTH" value="2"/>
|
||||
</attr>
|
||||
<!-- 设置字体全大写 -->
|
||||
<attr name="tl_textAllCaps" format="boolean"/>
|
||||
|
||||
<attr name="tl_showCateIndicator" format="boolean"/>
|
||||
|
||||
<declare-styleable name="SlidingTabLayout">
|
||||
<!-- indicator -->
|
||||
<attr name="tl_indicator_color"/>
|
||||
<attr name="tl_indicator_height"/>
|
||||
<attr name="tl_indicator_width"/>
|
||||
<attr name="tl_indicator_margin_left"/>
|
||||
<attr name="tl_indicator_margin_top"/>
|
||||
<attr name="tl_indicator_margin_right"/>
|
||||
<attr name="tl_indicator_margin_bottom"/>
|
||||
<attr name="tl_indicator_corner_radius"/>
|
||||
<attr name="tl_indicator_gravity"/>
|
||||
<attr name="tl_indicator_style"/>
|
||||
<attr name="tl_indicator_width_equal_title"/>
|
||||
<attr name="tl_indicator_drawable"/>
|
||||
|
||||
<!-- underline -->
|
||||
<attr name="tl_underline_color"/>
|
||||
<attr name="tl_underline_height"/>
|
||||
<attr name="tl_underline_gravity"/>
|
||||
|
||||
<!-- divider -->
|
||||
<attr name="tl_divider_color"/>
|
||||
<attr name="tl_divider_width"/>
|
||||
<attr name="tl_divider_padding"/>
|
||||
|
||||
<!-- tab -->
|
||||
<attr name="tl_tab_padding"/>
|
||||
<attr name="tl_tab_space_equal"/>
|
||||
<attr name="tl_tab_width"/>
|
||||
|
||||
<!-- title -->
|
||||
<attr name="tl_textsize"/>
|
||||
<attr name="tl_textSelectedSize"/>
|
||||
<attr name="tl_textSelectColor"/>
|
||||
<attr name="tl_textUnselectColor" />
|
||||
<attr name="tl_textBold"/>
|
||||
<attr name="tl_textAllCaps"/>
|
||||
<attr name="tl_showCateIndicator" />
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CommonTabLayout">
|
||||
<!-- indicator -->
|
||||
<attr name="tl_indicator_color"/>
|
||||
<attr name="tl_indicator_height"/>
|
||||
<attr name="tl_indicator_width"/>
|
||||
<attr name="tl_indicator_margin_left"/>
|
||||
<attr name="tl_indicator_margin_top"/>
|
||||
<attr name="tl_indicator_margin_right"/>
|
||||
<attr name="tl_indicator_margin_bottom"/>
|
||||
<attr name="tl_indicator_corner_radius"/>
|
||||
<attr name="tl_indicator_gravity"/>
|
||||
<attr name="tl_indicator_style"/>
|
||||
<attr name="tl_indicator_anim_enable"/>
|
||||
<attr name="tl_indicator_anim_duration"/>
|
||||
<attr name="tl_indicator_bounce_enable"/>
|
||||
|
||||
<!-- underline -->
|
||||
<attr name="tl_underline_color"/>
|
||||
<attr name="tl_underline_height"/>
|
||||
<attr name="tl_underline_gravity"/>
|
||||
|
||||
<!-- divider -->
|
||||
<attr name="tl_divider_color"/>
|
||||
<attr name="tl_divider_width"/>
|
||||
<attr name="tl_divider_padding"/>
|
||||
|
||||
<!-- tab -->
|
||||
<attr name="tl_tab_padding"/>
|
||||
<attr name="tl_tab_space_equal"/>
|
||||
<attr name="tl_tab_width"/>
|
||||
|
||||
<!-- title -->
|
||||
<attr name="tl_textsize"/>
|
||||
<attr name="tl_textSelectColor"/>
|
||||
<attr name="tl_textUnselectColor"/>
|
||||
<attr name="tl_textBold"/>
|
||||
<attr name="tl_textAllCaps"/>
|
||||
|
||||
<!-- icon -->
|
||||
<!-- 设置icon宽度 -->
|
||||
<attr name="tl_iconWidth" format="dimension"/>
|
||||
<!-- 设置icon高度 -->
|
||||
<attr name="tl_iconHeight" format="dimension"/>
|
||||
<!-- 设置icon是否可见 -->
|
||||
<attr name="tl_iconVisible" format="boolean"/>
|
||||
<!-- 设置icon显示位置,对应Gravity中常量值 -->
|
||||
<attr name="tl_iconGravity" format="enum">
|
||||
<enum name="LEFT" value="3"/>
|
||||
<enum name="TOP" value="48"/>
|
||||
<enum name="RIGHT" value="5"/>
|
||||
<enum name="BOTTOM" value="80"/>
|
||||
</attr>
|
||||
<!-- 设置icon与文字间距 -->
|
||||
<attr name="tl_iconMargin" format="dimension"/>
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SegmentTabLayout">
|
||||
<!-- indicator -->
|
||||
<attr name="tl_indicator_color"/>
|
||||
<attr name="tl_indicator_height"/>
|
||||
<attr name="tl_indicator_margin_left"/>
|
||||
<attr name="tl_indicator_margin_top"/>
|
||||
<attr name="tl_indicator_margin_right"/>
|
||||
<attr name="tl_indicator_margin_bottom"/>
|
||||
<attr name="tl_indicator_corner_radius"/>
|
||||
<attr name="tl_indicator_anim_enable"/>
|
||||
<attr name="tl_indicator_anim_duration"/>
|
||||
<attr name="tl_indicator_bounce_enable"/>
|
||||
|
||||
<!-- divider -->
|
||||
<attr name="tl_divider_color"/>
|
||||
<attr name="tl_divider_width"/>
|
||||
<attr name="tl_divider_padding"/>
|
||||
|
||||
<!-- tab -->
|
||||
<attr name="tl_tab_padding"/>
|
||||
<attr name="tl_tab_space_equal"/>
|
||||
<attr name="tl_tab_width"/>
|
||||
|
||||
<!-- title -->
|
||||
<attr name="tl_textsize"/>
|
||||
<attr name="tl_textSelectColor"/>
|
||||
<attr name="tl_textUnselectColor"/>
|
||||
<attr name="tl_textBold"/>
|
||||
<attr name="tl_textAllCaps"/>
|
||||
|
||||
<attr name="tl_bar_color" format="color"/>
|
||||
<attr name="tl_bar_stroke_color" format="color"/>
|
||||
<attr name="tl_bar_stroke_width" format="dimension"/>
|
||||
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="MsgView">
|
||||
<!-- 圆角矩形背景色 -->
|
||||
<attr name="mv_backgroundColor" format="color"/>
|
||||
<!-- 圆角弧度,单位dp-->
|
||||
<attr name="mv_cornerRadius" format="dimension"/>
|
||||
<!-- 圆角弧度,单位dp-->
|
||||
<attr name="mv_strokeWidth" format="dimension"/>
|
||||
<!-- 圆角边框颜色-->
|
||||
<attr name="mv_strokeColor" format="color"/>
|
||||
<!-- 圆角弧度是高度一半-->
|
||||
<attr name="mv_isRadiusHalfHeight" format="boolean"/>
|
||||
<!-- 圆角矩形宽高相等,取较宽高中大值-->
|
||||
<attr name="mv_isWidthHeightEqual" format="boolean"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="CustomImgSlidingTabLayout">
|
||||
<!-- indicator -->
|
||||
<attr name="tl_indicator_color"/>
|
||||
<attr name="tl_indicator_height"/>
|
||||
<attr name="tl_indicator_width"/>
|
||||
<attr name="tl_indicator_margin_left"/>
|
||||
<attr name="tl_indicator_margin_top"/>
|
||||
<attr name="tl_indicator_margin_right"/>
|
||||
<attr name="tl_indicator_margin_bottom"/>
|
||||
<attr name="tl_indicator_corner_radius"/>
|
||||
<attr name="tl_indicator_gravity"/>
|
||||
<attr name="tl_indicator_style"/>
|
||||
<attr name="tl_indicator_width_equal_title"/>
|
||||
|
||||
<!-- underline -->
|
||||
<attr name="tl_underline_color"/>
|
||||
<attr name="tl_underline_height"/>
|
||||
<attr name="tl_underline_gravity"/>
|
||||
|
||||
<!-- divider -->
|
||||
<attr name="tl_divider_color"/>
|
||||
<attr name="tl_divider_width"/>
|
||||
<attr name="tl_divider_padding"/>
|
||||
|
||||
<!-- tab -->
|
||||
<attr name="tl_tab_padding"/>
|
||||
<attr name="tl_tab_space_equal"/>
|
||||
<attr name="tl_tab_width"/>
|
||||
|
||||
<!-- title -->
|
||||
<attr name="tl_textSelectColor"/>
|
||||
<attr name="tl_textUnselectColor" />
|
||||
<attr name="tl_imgShowCateIndicator" format="boolean"/>
|
||||
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user