大家在开发项目的时候,如果新开发一个app,采用这种标签栏模式的产品,需要搭建底部菜单。
实现起来很简单,而且可以有消息提醒功能。话不多说,直接上代码:
核心的CommonTabLayout 自定义的FrameLayout
package com.example.commontablayoutdemo; 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.support.v4.app.Fragment; import android.support.v4.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 java.util.ArrayList; /** 没有继承HorizontalScrollView不能滑动,对于ViewPager无依赖 */ @SuppressLint("NewApi") 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); } @SuppressLint("NewApi") 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_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); } }