package com.sage.cmp.ui.exercise_project.view;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
/**
* AlphaTabsIndicator类
*/
public class AlphaTabsIndicator extends LinearLayout {
private ViewPager mViewPager;
private OnTabChangedListner mListner;
private List mTabViews;
private boolean ISINIT;
/**
* 子View的数量
*/
private int mChildCounts;
/**
* 当前的条目索引
*/
private int mCurrentItem = 0;
public AlphaTabsIndicator(Context context) {
this(context, null);
}
public AlphaTabsIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AlphaTabsIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
post(new Runnable() {
@Override
public void run() {
isInit();
}
});
}
public void setViewPager(ViewPager mViewPager) {
this.mViewPager = mViewPager;
init();
}
public void setOnTabChangedListner(OnTabChangedListner listner) {
this.mListner = listner;
isInit();
}
public AlphaTabView getCurrentItemView() {
isInit();
return mTabViews.get(mCurrentItem);
}
public AlphaTabView getTabView(int tabIndex) {
isInit();
return mTabViews.get(tabIndex);
}
public void removeAllBadge() {
isInit();
for (AlphaTabView alphaTabView : mTabViews) {
alphaTabView.removeShow();
}
}
public void setTabCurrenItem(int tabIndex) {
if (tabIndex < mChildCounts && tabIndex > -1) {
mTabViews.get(tabIndex).performClick();
} else {
throw new IllegalArgumentException("IndexOutOfBoundsException");
}
}
private void isInit() {
if (!ISINIT) {
init();
}
}
private void init() {
ISINIT = true;
mTabViews = new ArrayList<>();
mChildCounts = getChildCount();
if (null != mViewPager) {
if (null == mViewPager.getAdapter()) {
throw new NullPointerException("viewpager的adapter为null");
}
if (mViewPager.getAdapter().getCount() != mChildCounts) {
throw new IllegalArgumentException("子View数量必须和ViewPager条目数量一致");
}
//对ViewPager添加监听
mViewPager.addOnPageChangeListener(new MyOnPageChangeListener());
}
for (int i = 0; i < mChildCounts; i++) {
if (getChildAt(i) instanceof AlphaTabView) {
AlphaTabView tabView = (AlphaTabView) getChildAt(i);
mTabViews.add(tabView);
//设置点击监听
tabView.setOnClickListener(new MyOnClickListener(i));
} else {
throw new IllegalArgumentException("TabIndicator的子View必须是TabView");
}
}
mTabViews.get(mCurrentItem).setIconAlpha(1.0f);
}
private class MyOnPageChangeListener extends ViewPager.SimpleOnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//滑动时的透明度动画
if (positionOffset > 0) {
mTabViews.get(position).setIconAlpha(1 - positionOffset);
mTabViews.get(position + 1).setIconAlpha(positionOffset);
}
//滑动时保存当前按钮索引
mCurrentItem = position;
}
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
resetState();
mTabViews.get(position).setIconAlpha(1.0f);
mCurrentItem = position;
}
}
private class MyOnClickListener implements OnClickListener {
private int currentIndex;
public MyOnClickListener(int i) {
this.currentIndex = i;
}
@Override
public void onClick(View v) {
//点击前先重置所有按钮的状态
resetState();
mTabViews.get(currentIndex).setIconAlpha(1.0f);
if (null != mListner) {
mListner.onTabSelected(currentIndex);
}
if (null != mViewPager) {
//不能使用平滑滚动,否者颜色改变会乱
mViewPager.setCurrentItem(currentIndex, false);
}
//点击是保存当前按钮索引
mCurrentItem = currentIndex;
}
}
/**
* 重置所有按钮的状态
*/
private void resetState() {
for (int i = 0; i < mChildCounts; i++) {
mTabViews.get(i).setIconAlpha(0);
}
}
private static final String STATE_INSTANCE = "instance_state";
private static final String STATE_ITEM = "state_item";
/**
* @return 当View被销毁的时候,保存数据
*/
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
bundle.putInt(STATE_ITEM, mCurrentItem);
return bundle;
}
/**
* @param state 用于恢复数据使用
*/
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mCurrentItem = bundle.getInt(STATE_ITEM);
if (null == mTabViews || mTabViews.isEmpty()) {
super.onRestoreInstanceState(state);
return;
}
//重置所有按钮状态
resetState();
//恢复点击的条目颜色
mTabViews.get(mCurrentItem).setIconAlpha(1.0f);
super.onRestoreInstanceState(bundle.getParcelable(STATE_INSTANCE));
} else {
super.onRestoreInstanceState(state);
}
}
}
package com.sage.cmp.ui.exercise_project.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.sage.cmp.ui.exercise_project.R;
/**
* AlphaTabView 类
* 可以渐变的View
*/
public class AlphaTabView extends View {
private Context mContext; //上下文
private Bitmap mIconNormal; //默认图标
private Bitmap mIconSelected; //选中的图标
private String mText; //描述文本
private int mTextColorNormal = 0xFF999999; //描述文本的默认显示颜色
private int mTextColorSelected = 0xFF46C01B; //述文本的默认选中显示颜色
private int mTextSize = 12; //描述文本的默认字体大小 12sp
private int mPadding = 5; //文字和图片之间的距离 5dp
private float mAlpha; //当前的透明度
private Paint mSelectedPaint = new Paint(); //背景的画笔
private Rect mIconAvailableRect = new Rect(); //图标可用的绘制区域
private Rect mIconDrawRect = new Rect(); //图标真正的绘制区域
private Paint mTextPaint; //描述文本的画笔
private Rect mTextBound; //描述文本矩形测量大小
private Paint.FontMetricsInt mFmi; //用于获取字体的各种属性
private boolean isShowRemove; //是否移除当前角标
private boolean isShowPoint; //是否显示圆点
private int mBadgeNumber; //角标数
private int mBadgeBackgroundColor = 0xFFFF0000; //默认红颜色
public AlphaTabView(Context context) {
this(context, null);
mContext = context;
}
public AlphaTabView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
mContext = context;
}
public AlphaTabView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTextSize, getResources().getDisplayMetrics());
mPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPadding, getResources().getDisplayMetrics());
//获取所有的自定义属性
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AlphaTabView);
BitmapDrawable iconNormal = (BitmapDrawable) a.getDrawable(R.styleable.AlphaTabView_tabIconNormal);
if (iconNormal != null) {
mIconNormal = iconNormal.getBitmap();
}
BitmapDrawable iconSelected = (BitmapDrawable) a.getDrawable(R.styleable.AlphaTabView_tabIconSelected);
if (iconSelected != null) {
mIconSelected = iconSelected.getBitmap();
}
if (null != mIconNormal) {
mIconSelected = null == mIconSelected ? mIconNormal : mIconSelected;
} else {
mIconNormal = null == mIconSelected ? mIconNormal : mIconSelected;
}
mText = a.getString(R.styleable.AlphaTabView_tabText);
mTextSize = a.getDimensionPixelSize(R.styleable.AlphaTabView_tabTextSize, mTextSize);
mTextColorNormal = a.getColor(R.styleable.AlphaTabView_textColorNormal, mTextColorNormal);
mTextColorSelected = a.getColor(R.styleable.AlphaTabView_textColorSelected, mTextColorSelected);
mBadgeBackgroundColor = a.getColor(R.styleable.AlphaTabView_badgeBackgroundColor, mBadgeBackgroundColor);
mPadding = (int) a.getDimension(R.styleable.AlphaTabView_paddingTexwithIcon, mPadding);
a.recycle();
initText();
}
/**
* 如果有设置文字就获取文字的区域大小
*/
private void initText() {
if (mText != null) {
mTextBound = new Rect();
mTextPaint = new Paint();
mTextPaint.setTextSize(mTextSize);
mTextPaint.setAntiAlias(true);
mTextPaint.setDither(true);
mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
mFmi = mTextPaint.getFontMetricsInt();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mText == null && (mIconNormal == null || mIconSelected == null)) {
throw new IllegalArgumentException("必须设置 tabText 或者 tabIconSelected、tabIconNormal 两个,或者全部设置");
}
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
//计算出可用绘图的区域
int availableWidth = measuredWidth - paddingLeft - paddingRight;
int availableHeight = measuredHeight - paddingTop - paddingBottom;
if (mText != null && mIconNormal != null) {
availableHeight -= (mTextBound.height() + mPadding);
//计算出图标可以绘制的画布大小
mIconAvailableRect.set(paddingLeft, paddingTop, paddingLeft + availableWidth, paddingTop + availableHeight);
//计算文字的绘图区域
int textLeft = paddingLeft + (availableWidth - mTextBound.width()) / 2;
int textTop = mIconAvailableRect.bottom + mPadding;
mTextBound.set(textLeft, textTop, textLeft + mTextBound.width(), textTop + mTextBound.height());
} else if (mText == null) {
//计算出图标可以绘制的画布大小
mIconAvailableRect.set(paddingLeft, paddingTop, paddingLeft + availableWidth, paddingTop + availableHeight);
} else if (mIconNormal == null) {
//计算文字的绘图区域
int textLeft = paddingLeft + (availableWidth - mTextBound.width()) / 2;
int textTop = paddingTop + (availableHeight - mTextBound.height()) / 2;
mTextBound.set(textLeft, textTop, textLeft + mTextBound.width(), textTop + mTextBound.height());
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int alpha = (int) Math.ceil(mAlpha * 255);
if (mIconNormal != null && mIconSelected != null) {
Rect drawRect = availableToDrawRect(mIconAvailableRect, mIconNormal);
mSelectedPaint.reset();
mSelectedPaint.setAntiAlias(true);//设置抗锯齿
mSelectedPaint.setFilterBitmap(true);//抗锯齿
mSelectedPaint.setAlpha(255 - alpha);
canvas.drawBitmap(mIconNormal, null, drawRect, mSelectedPaint);
mSelectedPaint.reset();
mSelectedPaint.setAntiAlias(true);//设置抗锯齿
mSelectedPaint.setFilterBitmap(true);//抗锯齿
mSelectedPaint.setAlpha(alpha); //setAlpha必须放在paint的属性最后设置,否则不起作用
canvas.drawBitmap(mIconSelected, null, drawRect, mSelectedPaint);
}
if (mText != null) {
//绘制原始文字,setAlpha必须放在paint的属性最后设置,否则不起作用
mTextPaint.setColor(mTextColorNormal);
mTextPaint.setAlpha(255 - alpha);
//由于在该方法中,y轴坐标代表的是baseLine的值,经测试,mTextBound.height() + mFmi.bottom 就是字体的高
//所以在最后绘制前,修正偏移量,将文字向上修正 mFmi.bottom / 2 即可实现垂直居中
canvas.drawText(mText, mTextBound.left, mTextBound.bottom - mFmi.bottom / 2, mTextPaint);
//绘制变色文字,setAlpha必须放在paint的属性最后设置,否则不起作用
mTextPaint.setColor(mTextColorSelected);
mTextPaint.setAlpha(alpha);
canvas.drawText(mText, mTextBound.left, mTextBound.bottom - mFmi.bottom / 2, mTextPaint);
}
//绘制角标
if (!isShowRemove) {
drawBadge(canvas);
}
}
/**
* badge
*/
private void drawBadge(Canvas canvas) {
int i = getMeasuredWidth() / 14;
int j = getMeasuredHeight() / 9;
i = i >= j ? j : i;
if (mBadgeNumber > 0) {
Paint backgroundPaint = new Paint();
backgroundPaint.setColor(mBadgeBackgroundColor);
backgroundPaint.setAntiAlias(true);
String number = mBadgeNumber > 99 ? "99+" : String.valueOf(mBadgeNumber);
float textSize = i / 1.5f == 0 ? 5 : i / 1.5f;
int width;
int hight = (int) dp2px(mContext, i);
Bitmap bitmap;
if (number.length() == 1) {
width = (int) dp2px(mContext, i);
bitmap = Bitmap.createBitmap(width, hight, Bitmap.Config.ARGB_8888);
} else if (number.length() == 2) {
width = (int) dp2px(mContext, i + 5);
bitmap = Bitmap.createBitmap(width, hight, Bitmap.Config.ARGB_8888);
} else {
width = (int) dp2px(mContext, i + 8);
bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
}
Canvas canvasMessages = new Canvas(bitmap);
RectF messageRectF = new RectF(0, 0, width, hight);
canvasMessages.drawRoundRect(messageRectF, 50, 50, backgroundPaint); //画椭圆
Paint numberPaint = new Paint();
numberPaint.setColor(Color.WHITE);
numberPaint.setTextSize(dp2px(mContext, textSize));
numberPaint.setAntiAlias(true);
numberPaint.setTextAlign(Paint.Align.CENTER);
numberPaint.setTypeface(Typeface.DEFAULT_BOLD);
Paint.FontMetrics fontMetrics = numberPaint.getFontMetrics();
float x = width / 2f;
float y = hight / 2f - fontMetrics.descent + (fontMetrics.descent - fontMetrics.ascent) / 2;
canvasMessages.drawText(number, x, y, numberPaint);
float left = getMeasuredWidth() / 10 * 6f;
float top = dp2px(mContext, 5);
canvas.drawBitmap(bitmap, left, top, null);
bitmap.recycle();
} else if (mBadgeNumber == 0) {
} else {
if (isShowPoint) {
Paint paint = new Paint();
paint.setColor(mBadgeBackgroundColor);
paint.setAntiAlias(true);
float left = getMeasuredWidth() / 10 * 6f;
float top = dp2px(getContext(), 5);
i = i > 10 ? 10 : i;
float width = dp2px(getContext(), i);
RectF messageRectF = new RectF(left, top, left + width, top + width);
canvas.drawOval(messageRectF, paint);
}
}
}
public void showPoint() {
isShowRemove = false;
mBadgeNumber = -1;
isShowPoint = true;
invalidate();
}
public void showNumber(int badgeNum) {
isShowRemove = false;
isShowPoint = false;
mBadgeNumber = badgeNum;
if (badgeNum > 0) {
invalidate();
} else {
isShowRemove = true;
invalidate();
}
}
public void removeShow() {
mBadgeNumber = 0;
isShowPoint = false;
isShowRemove = true;
invalidate();
}
public int getBadgeNumber() {
return mBadgeNumber;
}
public boolean isShowPoint() {
return isShowPoint;
}
private Rect availableToDrawRect(Rect availableRect, Bitmap bitmap) {
float dx = 0, dy = 0;
float wRatio = availableRect.width() * 1.0f / bitmap.getWidth();
float hRatio = availableRect.height() * 1.0f / bitmap.getHeight();
if (wRatio > hRatio) {
dx = (availableRect.width() - hRatio * bitmap.getWidth()) / 2;
} else {
dy = (availableRect.height() - wRatio * bitmap.getHeight()) / 2;
}
int left = (int) (availableRect.left + dx + 0.5f);
int top = (int) (availableRect.top + dy + 0.5f);
int right = (int) (availableRect.right - dx + 0.5f);
int bottom = (int) (availableRect.bottom - dy + 0.5f);
mIconDrawRect.set(left, top, right, bottom);
return mIconDrawRect;
}
/**
* @param alpha 对外提供的设置透明度的方法,取值 0.0 ~ 1.0
*/
public void setIconAlpha(float alpha) {
if (alpha < 0 || alpha > 1) {
throw new IllegalArgumentException("透明度必须是 0.0 - 1.0");
}
mAlpha = alpha;
invalidateView();
}
/**
* 根据当前所在线程更新界面
*/
private void invalidateView() {
if (Looper.getMainLooper() == Looper.myLooper()) {
invalidate();
} else {
postInvalidate();
}
}
private float dp2px(Context context, float dipValue) {
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale);
}
}
/**
* tab监听回调
*/
public interface OnTabChangedListner {
void onTabSelected(int tabNum);
}
/**
* values文件下的attrs.xml
*/
UI界面的实现过程
/**
* activity_tab_alpha.xml
*/
package com.sage.cmp.ui.exercise_project;
import android.support.v4.view.ViewPager;
import com.sage.cmp.ui.exercise_project.ui.adapter.TabFragmentPagerAdapter;
import com.sage.cmp.ui.exercise_project.view.AlphaTabsIndicator;
/**
* AlphaTabActivity 类
* 是实现底部渐变效果的
*/
public class AlphaTabActivity extends BaseActivity {
private ViewPager mVP;
private AlphaTabsIndicator mTabsIndicator;
private TabFragmentPagerAdapter adapter;
@Override
protected int rootLayoutId() {
return R.layout.activity_tab_alpha;
}
@Override
protected void initOnCreate() {
initView();
setAdapter();
}
private void setAdapter() {
adapter=new TabFragmentPagerAdapter(getSupportFragmentManager(),this);
mVP.setAdapter(adapter);
mTabsIndicator.setViewPager(mVP);
}
private void initView() {
mVP = (ViewPager) findViewById(R.id.vp);
mTabsIndicator = (AlphaTabsIndicator) findViewById(R.id.tabs_indicator);
}
}
package com.sage.cmp.ui.exercise_project.ui.adapter;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.sage.cmp.ui.exercise_project.R;
import com.sage.cmp.ui.exercise_project.ui.fragment.CreateFragmentFactory;
/**
* FragmentPagerAdapter适配器,
*/
public class TabFragmentPagerAdapter extends FragmentPagerAdapter {
private String[] tabsTitle;
public TabFragmentPagerAdapter(FragmentManager fm, Context context) {
super(fm);
tabsTitle = context.getResources().getStringArray(R.array.tab_bottom_info);
}
@Override
public Fragment getItem(int position) {
return CreateFragmentFactory.createBaseFragmentFactory(position);
}
@Override
public int getCount() {
return tabsTitle.length;
}
}
参考gitHub网址:https://github.com/yingLanNull/AlphaTabsIndicator