自己撸一个简单的Viewpager指示器

自己撸一个简单的Viewpager指示器,也可以扩展不需要和viewpager绑定

该控件继承自LinearLayout,横线摆放了标签,然后根据需要在底部绘制横线

属性

定义属性
1
2
3
4
5
6
7
8
9
10
11
12
13
<declare-styleable name="TabIndicator">
<attr name="titles" format="string"/>
<attr name="indicator_height" format="dimension"/>
<attr name="indicator_color" format="color"/>
<attr name="text_color_normal" format="color"/>
<attr name="text_color_select" format="color"/>
<attr name="text_size" format="dimension"/>
<!--math均分填满布局,wrap均分包裹内容-->
<attr name="text_mode" format="enum">
<enum name="math" value="1"/>
<enum name="wrap" value="2"/>
</attr>
</declare-styleable>
解析属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public TabIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOrientation(HORIZONTAL);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TabIndicator);
int indicatorSize = ta.getDimensionPixelSize(R.styleable.TabIndicator_indicator_height,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2,
context.getResources().getDisplayMetrics()));
paint.setStrokeWidth(indicatorSize);
int indicatorColor = ta.getColor(R.styleable.TabIndicator_indicator_color, Color.parseColor("#333333"));
paint.setColor(indicatorColor);
mNormalColor = ta.getColor(R.styleable.TabIndicator_text_color_normal, Color.parseColor("#666666"));
mSelectColor = ta.getColor(R.styleable.TabIndicator_text_color_select, Color.parseColor("#333333"));
mTextSize = ta.getDimensionPixelSize(R.styleable.TabIndicator_text_size, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14,
context.getResources().getDisplayMetrics()));
mMode = ta.getInt(R.styleable.TabIndicator_text_mode, 1);
//设置标题
String title = ta.getString(R.styleable.TabIndicator_titles);
if (!TextUtils.isEmpty(title)) {
String[] strings = title.split("/");
setChildItems(Arrays.asList(strings));
}
ta.recycle();
}

添加标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void setChildItems(@NonNull List<String> items) {
if (items.size() == 0) {
return;
}
titles = items;
for (int i = 0; i < items.size(); i++) {
String text = items.get(i);
//设置属性和权重
TextView tv = new TextView(getContext());
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT);
lp.weight = 1;
tv.setLayoutParams(lp);
tv.setGravity(Gravity.CENTER);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
if (i == 0) {
tv.setTextColor(mSelectColor);
} else {
tv.setTextColor(mNormalColor);
}
tv.setText(text);
addView(tv);
tv.setId(i);
tv.setOnClickListener(this);
}
}

现在运行起来的效果和普通的LinearLayout没有区别,但是不是已经像那么回事了。

indicator1

绘制横条

ViewGrouponDraw方法默认是不绘制的所以我们用dispatchDraw绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (titles != null && titles.size() == getChildCount()) {
int measuredHeight = getMeasuredHeight();
int width = getMeasuredWidth() / getChildCount();
int y = (int) (measuredHeight - paint.getStrokeWidth() / 2);
//移动画布的方式来画横线,mTranslationX也就是移动的距离
canvas.translate(mTranslationX, 0);
if (mMode == 2) {//包裹
int round = (int) Math.round(mTranslationX * 1.0 / width);
if (round < getChildCount()) {
String text = titles.get(round);
float size = text.length() * mTextSize;
canvas.drawLine((width - size) / 2, y, (width + size) / 2, y, paint);
}
} else {//填满
canvas.drawLine(0, y, width, y, paint);
}
}
}

现在已经有点指示器的样子了,但是mTranslationX是0,所以只有静态效果,接下然让它动起来

与ViewPager关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void setupWithVp(ViewPager vp) {
this.mViewPager = vp;
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float offset, int positionOffsetPixels) {
//viewpager滑动多少我也相对滑动多少
mTranslationX = (int) (getWidth() / getChildCount() * (position + offset));
invalidate();
}
@Override
public void onPageSelected(int position) {
int count = getChildCount();
if (count - 1 >= position) {
for (int i = 0; i < count; i++) {//设置被选择的的标签字体颜色
((TextView) getChildAt(i)).setTextColor(mNormalColor);
}
((TextView) getChildAt(position)).setTextColor(mSelectColor);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public void onClick(View v) {![indicator2](D:\myblog\source\_posts\indicator2.png)
if (mViewPager != null) {//点击标签,切换viewpager
mViewPager.setCurrentItem(v.getId());
return;
}
}

运行起来后你就会发现和系统的效果一模一样了,其实代码很简单,所以还有很大的改进空间。