前言
系統(tǒng)自帶的Tablayout用的也不錯但是有些功能還不能滿足我們這邊開發(fā),所以我這邊自定義了一個tablayout提供了自定義tab線的長度以及,移動速度,以及禁止某個滑動(tablayout基本功能也提供了)
效果圖

QQ20170327-165412-HD(1).gif
實現(xiàn)步驟
- 構(gòu)造方法添加子控件
添加一些xml定義的屬性
public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setGravity(Gravity.CENTER_VERTICAL);
this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Indicator, 0, 0);
mColor = array.getColor(R.styleable.Indicator_indicatorColor, Color.RED);
mList = getContext().getResources().getStringArray(array.getResourceId(R.styleable.Indicator_array, 0));
mTextNomal = array.getInteger(R.styleable.Indicator_text_nomal_size, 12);
mTextPress = array.getInteger(R.styleable.Indicator_text_press_size, 13);
mText_Nomal = array.getColor(R.styleable.Indicator_text_nomal_color, Color.GRAY);
mText_Press = array.getColor(R.styleable.Indicator_text_press_color, Color.BLACK);
mSelected = array.getInteger(R.styleable.Indicator_selected, 0);
isFull = array.getBoolean(R.styleable.Indicator_isFull, false);
mAnimationTime = array.getInteger(R.styleable.Indicator_speed, 300);
mBai = array.getFloat(R.styleable.Indicator_multiply, (float) 1.2);
mHeight = array.getInteger(R.styleable.Indicator_line_hegith, 5);
for (int i = 0; i < mList.length; i++) {
mListTitle.add(mList[i]);
}
array.recycle();
}
- onLayout初始化布局
添加控件
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (!mIsCheck) {
mIsCheck = true;
initView();
}
}
添加textview以及線
/**
* 初始化布局
*/
private void initView() {
measure(0, 0);
//獲取每個textview布局所占的寬度
mContWidth = getWidth() / mListTitle.size();
//添加線
mLine = new View(getContext());
addView(mLine);
int mWeight;
if (isFull) {
mWeight = mContWidth;
} else {
mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);
if (mWeight > mContWidth) {
mWeight = mContWidth;
}
}
//設(shè)置線的基本屬性
LayoutParams mLayoutParams1 = new LayoutParams(mWeight, mHeight);
mLayoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
mLine.setLayoutParams(mLayoutParams1);
mLine.setBackgroundColor(mColor);
//獲取上一次所在位置
mEndAddress = mContWidth * mSelected + (mContWidth - mWeight) / 2;
//添加textview
for (int i = 0; i < mListTitle.size(); i++) {
addTextView(i);
}
//初始化點擊事件
setListener();
}
/**
* 添加textview
*/
private void addTextView(int i) {
//初始化textview
TextView textView = new TextView(getContext());
textView.setText(mListTitle.get(i));
//設(shè)置textview基本屬性
LayoutParams mLayoutParams = new LayoutParams(mContWidth, LayoutParams.MATCH_PARENT);
mLayoutParams.leftMargin = mContWidth * i;
mLayoutParams.addRule(CENTER_VERTICAL);
textView.setLayoutParams(mLayoutParams);
textView.setGravity(Gravity.CENTER);
if (i == mSelected) {
textView.setTextColor(mText_Press);
textView.setTextSize(mTextPress);
} else {
textView.setTextColor(mText_Nomal);
textView.setTextSize(mTextNomal);
}
//添加textview到布局
mTextList.add(textView);
addView(textView);
}
- 動畫
動畫就簡單了直接一個移動動畫就好了
/**
* 動畫
*
* @param statX 開始位置
* @param endX 結(jié)束位置
*/
private void setAnimation(int statX, int endX) {
AnimationSet mSet = new AnimationSet(true);
TranslateAnimation translate1 = new TranslateAnimation(
statX, endX, 0, 0);
mSet.addAnimation(translate1);
mSet.setFillAfter(true);
mSet.setDuration(mAnimationTime);
mLine.startAnimation(mSet);
}
- 修改下標位置
計算修改下標的位置
/**
* 改變下標
*
* @param position
*/
public void setChanger(int position) {
//改為默認字體顏色修改選中字體顏色
resetColor();
mTextList.get(position).setTextColor(mText_Press);
mTextList.get(position).setTextSize(mTextPress);
mSelected = position;
int mWeight;
if (isFull) {
mWeight = mContWidth;
} else {
mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);
if (mWeight > mContWidth) {
mWeight = mContWidth;
}
}
/**
* 計算當前選擇textview的X點位置
*/
int way = mContWidth * mSelected + (mContWidth - mWeight) / 2;
LayoutParams mLayoutParams = new LayoutParams(mWeight, mHeight);
mLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
mLine.setLayoutParams(mLayoutParams);
setAnimation(mEndAddress, way);
mEndAddress = way;
this.mNowPosition = position;
}
- XML部分屬性
線的顏色 : indicatorColor (默認red)
textview顯示數(shù)組 :array
字體默認顏色:text_nomal_color (默認gray)
字體選中顏色:text_press_color (默認black)
字體默認大?。簍ext_press_color (默認12)
字體選中大?。簍ext_press_size (默認13)
默認選中:selected (默認0)
線是否鋪滿:isFull (默認false)
移動速度:speed (默認300)
線是字體的倍數(shù):multiply (默認1.2)
線的高度: multiply (默認5)
<declare-styleable name="Indicator">
<attr name="indicatorColor" format="color"/>
<attr name="array" format="integer"/>
<attr name="text_nomal_color" format="color"/>
<attr name="text_press_color" format="color"/>
<attr name="text_nomal_size" format="integer"/>
<attr name="text_press_size" format="integer"/>
<attr name="selected" format="integer"/>
<attr name="isFull" format="boolean"/>
<attr name="speed" format="integer"/>
<attr name="multiply" format="float"/>
<attr name="line_hegith" format="integer"/>
</declare-styleable>
自定義控件代碼獻上
- JAVA代碼
/**
* Created by huangbo on 17/1/22.
* 指示器
*/
public class MyIndicator extends RelativeLayout {
/**
* 線的顏色
*/
private int mColor;
/**
* 線的高度
*/
private int mHeight;
/**
* xml數(shù)組
*/
private String[] mList;
/**
* textview數(shù)組
*/
private List<TextView> mTextList = new ArrayList<>();
/**
* string數(shù)組
*/
private List<String> mListTitle = new ArrayList<>();
/**
* 默認字體大小
*/
private int mTextNomal;
/**
* 被選擇字體大小
*/
private int mTextPress;
/**
* 默認字體顏色
*/
private int mText_Nomal;
/**
* 被選擇的顏色
*/
private int mText_Press;
/**
* 每個格子個長度
*/
private int mContWidth;
/**
* 被選擇的tab
*/
private int mSelected;
/**
* 底線
*/
private View mLine;
/**
* 是否或去過
*/
private boolean mIsCheck;
/**
* 字體的多少倍
*/
private float mBai;
/**
* 記錄移動結(jié)束位置
*/
private int mEndAddress;
/**
* 禁止滑動表情下標
*/
private int mProhibitPisition = -1;
/**
* 動畫時間
*/
private int mAnimationTime;
/**
* 當前選中
*/
private int mNowPosition;
/**
* 是否鋪滿
*/
private boolean isFull;
public MyIndicator(Context context) {
this(context, null);
}
public MyIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setGravity(Gravity.CENTER_VERTICAL);
this.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Indicator, 0, 0);
mColor = array.getColor(R.styleable.Indicator_indicatorColor, Color.RED);
mList = getContext().getResources().getStringArray(array.getResourceId(R.styleable.Indicator_array, 0));
mTextNomal = array.getInteger(R.styleable.Indicator_text_nomal_size, 12);
mTextPress = array.getInteger(R.styleable.Indicator_text_press_size, 13);
mText_Nomal = array.getColor(R.styleable.Indicator_text_nomal_color, Color.GRAY);
mText_Press = array.getColor(R.styleable.Indicator_text_press_color, Color.BLACK);
mSelected = array.getInteger(R.styleable.Indicator_selected, 0);
isFull = array.getBoolean(R.styleable.Indicator_isFull, false);
mAnimationTime = array.getInteger(R.styleable.Indicator_speed, 300);
mBai = array.getFloat(R.styleable.Indicator_multiply, (float) 1.2);
mHeight = array.getInteger(R.styleable.Indicator_line_hegith, 5);
for (int i = 0; i < mList.length; i++) {
mListTitle.add(mList[i]);
}
array.recycle();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (!mIsCheck) {
mIsCheck = true;
initView();
}
}
/**
* 初始化布局
*/
private void initView() {
measure(0, 0);
//獲取每個textview布局所占的寬度
mContWidth = getWidth() / mListTitle.size();
//添加線
mLine = new View(getContext());
addView(mLine);
int mWeight;
if (isFull) {
mWeight = mContWidth;
} else {
mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);
if (mWeight > mContWidth) {
mWeight = mContWidth;
}
}
//設(shè)置線的基本屬性
LayoutParams mLayoutParams1 = new LayoutParams(mWeight, mHeight);
mLayoutParams1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
mLine.setLayoutParams(mLayoutParams1);
mLine.setBackgroundColor(mColor);
//獲取上一次所在位置
mEndAddress = mContWidth * mSelected + (mContWidth - mWeight) / 2;
//添加textview
for (int i = 0; i < mListTitle.size(); i++) {
addTextView(i);
}
//初始化點擊事件
setListener();
}
/**
* 添加textview
*/
private void addTextView(int i) {
//初始化textview
TextView textView = new TextView(getContext());
textView.setText(mListTitle.get(i));
//設(shè)置textview基本屬性
LayoutParams mLayoutParams = new LayoutParams(mContWidth, LayoutParams.MATCH_PARENT);
mLayoutParams.leftMargin = mContWidth * i;
mLayoutParams.addRule(CENTER_VERTICAL);
textView.setLayoutParams(mLayoutParams);
textView.setGravity(Gravity.CENTER);
if (i == mSelected) {
textView.setTextColor(mText_Press);
textView.setTextSize(mTextPress);
} else {
textView.setTextColor(mText_Nomal);
textView.setTextSize(mTextNomal);
}
//添加textview到布局
mTextList.add(textView);
addView(textView);
}
/**
* 清空字體顏色
*/
private void resetColor() {
for (int i = 0; i < mTextList.size(); i++) {
mTextList.get(i).setTextColor(getContext().getResources().getColor(R.color.text_hint));
}
}
/**
* 點擊tab事件
*/
private void setListener() {
setAnimation(0, mEndAddress);
for (int i = 0; i < mTextList.size(); i++) {
final int finalI = i;
mTextList.get(i).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (finalI != mSelected && mProhibitPisition != finalI) {
setChanger(finalI);
}
if (mOnIndiacatorClickListener != null)
mOnIndiacatorClickListener.onClick(finalI, v);
}
});
}
}
/**
* 動畫
*
* @param statX 開始位置
* @param endX 結(jié)束位置
*/
private void setAnimation(int statX, int endX) {
AnimationSet mSet = new AnimationSet(true);
TranslateAnimation translate1 = new TranslateAnimation(
statX, endX, 0, 0);
mSet.addAnimation(translate1);
mSet.setFillAfter(true);
mSet.setDuration(mAnimationTime);
mLine.startAnimation(mSet);
}
private OnIndiacatorClickListener mOnIndiacatorClickListener;
/**
* 計算下劃線長度
*/
private int setLineLength(String mTextView) {
return ConvertUtils.dp2px(mTextView.length() * mTextPress);
}
/**
* 添加頁面
*
* @param charSequence
*/
public void add(CharSequence charSequence, int position) {
removeAllViews();
mTextList.clear();
if (mListTitle.size() == position)
mListTitle.set(position - 1, charSequence.toString());
else
mListTitle.add(charSequence.toString());
initView();
}
/**
* 設(shè)置是否鋪滿
*/
public void setFull() {
isFull = true;
}
/**
* 設(shè)置監(jiān)聽
*
* @param onIndiacatorClickListener
*/
public void setIndiacatorListener(OnIndiacatorClickListener onIndiacatorClickListener) {
if (onIndiacatorClickListener != null) {
this.mOnIndiacatorClickListener = onIndiacatorClickListener;
}
}
/**
* 設(shè)置禁止滑動頁面
*
* @param i
*/
public void setProhibitPositio(int i) {
this.mProhibitPisition = i;
}
/**
* 設(shè)置動畫時間
*/
public void setAnimationTime(int time) {
this.mAnimationTime = time;
}
/**
* 外部監(jiān)聽
*/
public interface OnIndiacatorClickListener {
void onClick(int position, View view);
}
/**
* 改變下標
*
* @param position
*/
public void setChanger(int position) {
//改為默認字體顏色修改選中字體顏色
resetColor();
mTextList.get(position).setTextColor(mText_Press);
mTextList.get(position).setTextSize(mTextPress);
mSelected = position;
int mWeight;
if (isFull) {
mWeight = mContWidth;
} else {
mWeight = (int) (setLineLength(mListTitle.get(mSelected)) * mBai);
if (mWeight > mContWidth) {
mWeight = mContWidth;
}
}
/**
* 計算當前選擇textview的X點位置
*/
int way = mContWidth * mSelected + (mContWidth - mWeight) / 2;
LayoutParams mLayoutParams = new LayoutParams(mWeight, mHeight);
mLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
mLine.setLayoutParams(mLayoutParams);
setAnimation(mEndAddress, way);
mEndAddress = way;
this.mNowPosition = position;
}
/**
* 獲取當前下標
*/
public int getPosition() {
return mNowPosition;
}
}
- XML基本使用代碼
<demo.com.androiddemo.MyIndicator
android:id="@+id/my"
android:layout_width="match_parent"
android:layout_height="50dp"
app:array="@array/tabs"
app:indicatorColor="@color/btn_red"
app:selected="0"
app:text_nomal_color="@color/text_hint"
app:text_nomal_size="12"
app:text_press_color="@color/text_title"
app:text_press_size="13"
>
</demo.com.androiddemo.MyIndicator>
結(jié)語
客官看完肯定覺得非常簡單,每個人的思路不一樣實現(xiàn)的方式也有很多,如果覺得我的實現(xiàn)方式有問題或者好的實現(xiàn)方式可以給我留言,當然如果有什么特殊需求的話也可以留言給我,我?guī)湍銈兲峁┫嚓P(guān)需求,以后還會繼續(xù)更新相關(guān)博客希望各位給一個支持
地址
項目github地址:GitHub
依賴
compile 'com.github.q1104133609:MyTabLayout:v0.0.1'