一、问题背景
在我们实际卡法需求中可能会要修改tablayout下方的indicator的样式与属性,比如indicator的长度,或者给tablayout加个背景但是需要indicator滑动的效果,然而原生的tablayout却仅仅提供了tablayout的height即厚度的属性,自定义化的程度很低。
二、问题探索
通过查阅源码,发现tablayout的下划线是由其内部类SlidingTabStrip实现,其继承自LinearLayout布局的viewgroup。源码如下
private class SlidingTabStrip extends LinearLayout {
private int mSelectedIndicatorHeight;
private final Paint mSelectedIndicatorPaint;
int mSelectedPosition = -1;
float mSelectionOffset;
private int mLayoutDirection = -1;
private int mIndicatorLeft = -1;
private int mIndicatorRight = -1;
private ValueAnimator mIndicatorAnimator;
SlidingTabStrip(Context context) {
super(context);
setWillNotDraw(false);
mSelectedIndicatorPaint = new Paint();
}
...
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
// Thick colored underline below the current selection
if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
canvas.drawRect(mIndicatorLeft, getHeight() -
mSelectedIndicatorHeight,mIndicatorRight,
getHeight(), mSelectedIndicatorPaint);
}
}
省略部分细节代码,查看其ondraw方法会发现其绘制过程和三个变量相关:mSelectedIndicatorHeight,mIndicatorLeft 和mIndicatorRight ,由于mSelectedIndicatorHeight有提供接口可以改变可忽略,实际控制其绘制过程的为剩下俩个变量。
三、问题解决方案
正如上述缩分析的,控制SlidingTabStrip的绘制过程的为mIndicatorLeft 和mIndicatorRight 俩个变量,这俩个变量同时也是控制其位置显示的变量,只要获取到这俩个变量其实就可以进行我们自定义Indicator的封装,那么如何获取这俩个变量呢?——反射
//自定义drawable
public class IndicatorDrawable extends Drawable{
View view;
Paint paint;
float paddingLeft;
float paddingTop;
public IndicatorDrawable(View view) {
this.view = view;
paint = new Paint();
paint.setColor(Color.parseColor("#0f0"));
float density = view.getResources().getDisplayMetrics().density;
//这两个留白可以根据需求更改
paddingLeft = 0 * density;
paddingTop = 5 * density;
}
@Override
public void draw(@NonNull Canvas canvas) {
//自定义背景
int mIndicatorLeft = getIntValue("mIndicatorLeft");
int mIndicatorRight = getIntValue("mIndicatorRight");
int height = view.getHeight();
int radius = height / 2;
if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
//canvas.drawRoundRect(new RectF(mIndicatorLeft + (int)paddingLeft, (int)paddingTop, mIndicatorRight - (int)paddingLeft, height - (int)paddingTop), radius, radius, paint);
//缩减indicator的宽度
canvas.drawRect(mIndicatorLeft+40, height - 4,
mIndicatorRight-40, height, paint);
}
}
int getIntValue(String name) {
try {
Field f = view.getClass().getDeclaredField(name);
f.setAccessible(true);
Object obj = f.get(view);
return (Integer) obj;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
@Override
public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}