version:5.8

fix:
update:优化拨打电话页面
This commit is contained in:
2024-06-28 09:57:18 +08:00
parent 3ae9fd54ee
commit f8c9237dbb
58 changed files with 6537 additions and 484 deletions

1
FlycoTabLayoutZ_Lib/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,38 @@
apply plugin: 'com.android.library'
//apply plugin: 'com.novoda.bintray-release'
version = "1.3.3"
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
minSdkVersion 17
targetSdkVersion 28
versionCode 5
versionName version
}
buildTypes {
U807Debug {}
U807Release {}
iPlay50SEDebug {}
iPlay50SERelease {}
debug {}
release {}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
}
//// jcenter发布的信息
//publish {
// userOrg = 'lizp' // 创建repo的位置
// groupId = 'com.lzp' // 引用的分组名称
// artifactId = 'FlycoTabLayoutZ'//项目名称
// publishVersion = version//版本号
// desc = '在FlycoTabLayout的基础上扩展出SlidingScaleTabLayout实现滑动可以改变tab字体的大小的切换效果'
// website = 'https://github.com/li504799868/FlycoTabLayoutZ'
//}

17
FlycoTabLayoutZ_Lib/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/lihui/work/AndroidStudio/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}

View File

@@ -0,0 +1,3 @@
<manifest
package="com.flyco.tablayout">
</manifest>

View File

@@ -0,0 +1,985 @@
package com.flyco.tablayout;
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.Path;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Parcelable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
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 com.flyco.tablayout.listener.CustomTabEntity;
import com.flyco.tablayout.listener.OnTabSelectListener;
import com.flyco.tablayout.utils.FragmentChangeManager;
import com.flyco.tablayout.utils.UnreadMsgUtils;
import com.flyco.tablayout.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};
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_WHEN_SELECT && i == mCurrentTab) {
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);
}
}
/**
* 设置提示红点偏移,注意
* 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);
}
}

View File

@@ -0,0 +1,775 @@
package com.flyco.tablayout;
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 androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
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 com.flyco.tablayout.listener.OnTabSelectListener;
import com.flyco.tablayout.utils.FragmentChangeManager;
import com.flyco.tablayout.utils.UnreadMsgUtils;
import com.flyco.tablayout.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_WHEN_SELECT && i == mCurrentTab) {
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);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
package com.flyco.tablayout.listener;
import androidx.annotation.DrawableRes;
public interface CustomTabEntity {
String getTabTitle();
@DrawableRes
int getTabSelectedIcon();
@DrawableRes
int getTabUnselectedIcon();
}

View File

@@ -0,0 +1,6 @@
package com.flyco.tablayout.listener;
public interface OnTabSelectListener {
void onTabSelect(int position);
void onTabReselect(int position);
}

View File

@@ -0,0 +1,52 @@
package com.flyco.tablayout.transformer;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.ViewPager;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* Created by li.zhipeng on 2019/1/3.
* <p>
* tab切换的
*/
public class ExtendTransformer implements ViewPager.PageTransformer {
private ArrayList<IViewPagerTransformer> transformers = new ArrayList<>();
public ExtendTransformer() {
}
public void addViewPagerTransformer(IViewPagerTransformer transformer) {
if (!transformers.contains(transformer)) {
transformers.add(transformer);
}
}
public void removeViewPagerTransformer(IViewPagerTransformer transformer) {
transformers.remove(transformer);
}
public List<IViewPagerTransformer> getTransformers() {
return transformers;
}
public void setTransformers(List<IViewPagerTransformer> transformers) {
this.transformers.addAll(transformers);
}
@Override
public void transformPage(@NonNull View view, final float position) {
// 回调设置的页面切换效果设置
if (transformers != null && transformers.size() > 0) {
for (IViewPagerTransformer transformer : transformers) {
transformer.transformPage(view, position);
}
}
}
}

View File

@@ -0,0 +1,6 @@
package com.flyco.tablayout.transformer;
public interface ITabScaleTransformer {
void setNormalWidth(int position, int width, boolean isSelect);
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
}

View File

@@ -0,0 +1,12 @@
package com.flyco.tablayout.transformer;
import androidx.viewpager.widget.ViewPager;
/**
* Created by li.zhipeng on 2019/1/3.
*
* ViewPager的扩展Transformer配合SlidingScaleTabLayout使用
* 因为字体的切换效果设置了默认的Transformer所以扩展此接口
*/
public interface IViewPagerTransformer extends ViewPager.PageTransformer {
}

View File

@@ -0,0 +1,110 @@
package com.flyco.tablayout.transformer;
import android.util.Log;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.flyco.tablayout.SlidingScaleTabLayout;
/**
* Created by li.zhipeng on 2019/1/3.
* <p>
* tab切换的
*/
public class TabScaleTransformer implements ITabScaleTransformer {
private SlidingScaleTabLayout slidingScaleTabLayout;
private float textSelectSize;
private float textUnSelectSize;
// private float maxScale;
private boolean openDmg;
public TabScaleTransformer(SlidingScaleTabLayout slidingScaleTabLayout,
float textSelectSize, float textUnSelectSize, boolean openDmg) {
this.slidingScaleTabLayout = slidingScaleTabLayout;
this.textSelectSize = textSelectSize;
this.textUnSelectSize = textUnSelectSize;
// this.maxScale = (textSelectSize / textUnSelectSize) - 1;
this.openDmg = openDmg;
}
@Override
public void setNormalWidth(int position, int width, boolean isSelect) {
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
Log.i("TabScaleTransformer", "position:" + position);
// 字体大小相同,不需要切换
if (textSelectSize == textUnSelectSize) return;
if (openDmg) {
for (int i = 0; i < slidingScaleTabLayout.getTabCount(); i++) {
if (i != position && i != position + 1) {
changTabDmgWidth(i, 0);
}
}
changeDmgSize(position, positionOffset);
} else {
for (int i = 0; i < slidingScaleTabLayout.getTabCount(); i++) {
if (i != position && i != position + 1) {
updateTextSize(i, 1);
}
}
changeTextSize(position, positionOffset);
}
}
private void changeTextSize(final int position, final float positionOffset) {
updateTextSize(position, positionOffset);
if (position + 1 < slidingScaleTabLayout.getTabCount()) {
updateTextSize(position + 1, 1 - positionOffset);
}
}
private void updateTextSize(final int position, final float positionOffset) {
final TextView currentTab = slidingScaleTabLayout.getTitle(position);
// 必须要在View调用post更新样式否则可能无效
currentTab.post(new Runnable() {
@Override
public void run() {
int textSize = (int) (textSelectSize - Math.abs((textSelectSize - textUnSelectSize) * positionOffset));
if (currentTab.getTextSize() != textSize) {
currentTab.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
currentTab.requestLayout();
}
}
});
}
private void changeDmgSize(final int position, final float positionOffset) {
slidingScaleTabLayout.post(new Runnable() {
@Override
public void run() {
// Log.i("lzp", "position:" + position + " positionOffset" + positionOffset);
float scale = 1 - positionOffset;
changTabDmgWidth(position, scale);
if (position + 1 < slidingScaleTabLayout.getTabCount()) {
changTabDmgWidth(position + 1, positionOffset);
}
}
});
}
private void changTabDmgWidth(int position, float scale) {
final ImageView currentTabDmg = slidingScaleTabLayout.getDmgView(position);
if (currentTabDmg == null) return;
if (currentTabDmg.getDrawable() == null) return;
ViewGroup.LayoutParams params = currentTabDmg.getLayoutParams();
int width = (int) (currentTabDmg.getMinimumWidth() + (currentTabDmg.getMaxWidth() - currentTabDmg.getMinimumWidth()) * scale);
if (params.width != width) {
params.width = width;
currentTabDmg.setLayoutParams(params);
}
// Log.i("lzp", "position:" + position + " scale" + scale + " width:" + params.width);
}
}

View File

@@ -0,0 +1,55 @@
package com.flyco.tablayout.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);
}
}

View File

@@ -0,0 +1,58 @@
package com.flyco.tablayout.utils;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.RelativeLayout;
import com.flyco.tablayout.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 < 10) {//圆
lp.width = (int) (18 * dm.density);
msgView.setText(num + "");
} else if (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);
}
}

View File

@@ -0,0 +1,39 @@
package com.flyco.tablayout.utils;
import android.graphics.Bitmap;
import androidx.annotation.IdRes;
import android.view.View;
public class ViewUtils {
public static Bitmap generateViewCacheBitmap(View view) {
view.destroyDrawingCache();
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
view.layout(0, 0, width, height);
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
return Bitmap.createBitmap(view.getDrawingCache());
}
public static View findBrotherView(View view, @IdRes int id, int level) {
int count = 0;
View temp = view;
while (count < level) {
View target = temp.findViewById(id);
if (target != null) {
return target;
}
count += 1;
if (temp.getParent() instanceof View) {
temp = (View) temp.getParent();
} else {
break;
}
}
return null;
}
}

View File

@@ -0,0 +1,157 @@
package com.flyco.tablayout.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.flyco.tablayout.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);
}
}
}

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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:includeFontPadding="false"
tools:text="111"
android:singleLine="true" />
<ImageView
android:id="@+id/tv_tab_title_dmg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<com.flyco.tablayout.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"
tools:visibility="visible" />
</RelativeLayout>

View File

@@ -0,0 +1,31 @@
<?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"/>
<com.flyco.tablayout.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: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>

View 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.flyco.tablayout.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>

View 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.flyco.tablayout.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>

View 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.flyco.tablayout.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>

View 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.flyco.tablayout.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>

View 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.flyco.tablayout.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>

View File

@@ -0,0 +1,319 @@
<?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" />
<!-- 设置显示器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" />
<!-- 设置tab的上下间距 -->
<attr name="tl_tab_marginTop" format="dimension" />
<attr name="tl_tab_marginBottom" format="dimension" />
<attr name="tl_tab_msg_marginTop" format="dimension" />
<attr name="tl_tab_msg_marginRight" format="dimension" />
<attr name="tl_tab_dot_marginTop" format="dimension" />
<attr name="tl_tab_dot_marginRight" format="dimension" />
<attr name="tl_tab_background" format="reference" />
<!-- tab的位置 -->
<attr name="tl_tab_gravity" format="enum">
<enum name="Top" value="0" />
<enum name="Bottom" value="1" />
<enum name="Center" value="2" />
</attr>
<!-- tab的竖直位置 -->
<attr name="tl_tab_vertical_gravity" format="enum">
<enum name="Top" value="0" />
<enum name="Bottom" value="1" />
<enum name="Center" value="2" />
</attr>
<!-- tab的水平位置 -->
<attr name="tl_tab_horizontal_gravity" format="enum">
<enum name="Left" value="0" />
<enum name="Right" value="1" />
<enum name="Center" value="2" />
</attr>
<!-- title -->
<!-- 设置字体大小 -->
<attr name="tl_textSize" format="dimension" />
<attr name="tl_textSelectSize" format="dimension" />
<attr name="tl_textUnSelectSize" 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" />
<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" />
<!-- 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" />
<attr name="tl_tab_marginTop" />
<attr name="tl_tab_marginBottom" />
<attr name="tl_tab_gravity" />
<!-- title -->
<attr name="tl_textSelectSize" />
<attr name="tl_textUnSelectSize" />
<attr name="tl_textSelectColor" />
<attr name="tl_textUnSelectColor" />
<attr name="tl_textBold" />
<attr name="tl_textAllCaps" />
</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="SlidingScaleTabLayout">
<!-- 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" />
<attr name="tl_tab_marginTop" />
<attr name="tl_tab_marginBottom" />
<attr name="tl_tab_horizontal_gravity" />
<attr name="tl_tab_vertical_gravity" />
<attr name="tl_tab_background" />
<!-- title -->
<attr name="tl_textSelectSize" />
<attr name="tl_textUnSelectSize" />
<attr name="tl_textSelectColor" />
<attr name="tl_textUnSelectColor" />
<attr name="tl_textBold" />
<attr name="tl_textAllCaps" />
<!-- 是否开启文字的图片镜像 -->
<attr name="tl_openTextDmg" format="boolean" />
<!-- 未读消息的位置 -->
<attr name="tl_tab_msg_marginTop" />
<attr name="tl_tab_msg_marginRight" />
<!-- 红点的位置 -->
<attr name="tl_tab_dot_marginTop" />
<attr name="tl_tab_dot_marginRight" />
</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>
</resources>