优雅修改参考优雅修改指示器
上面修改是通过自定义一个drawable,如果我项目中有多个宽度的指示器,那不就得产生多个drawable,本人比较懒不是很想这样,那如何在不修改源码的基础上,指定宽度呢,有人说反射,但是我用了AspectJ,具体为什么我待会说 首先先看源码:
@Override
public void draw(@NonNull Canvas canvas) {
if (indicatorLeft >= 0 && indicatorRight > indicatorLeft) {
Drawable selectedIndicator;
selectedIndicator =
DrawableCompat.wrap(
tabSelectedIndicator != null ? tabSelectedIndicator : defaultSelectionIndicator)
.mutate();
selectedIndicator.setBounds(indicatorLeft, indicatorTop, indicatorRight, indicatorBottom);
if (selectedIndicatorPaint != null) {
if (VERSION.SDK_INT == VERSION_CODES.LOLLIPOP) {
// Drawable doesn't implement setTint in API 21
selectedIndicator.setColorFilter(
selectedIndicatorPaint.getColor(), PorterDuff.Mode.SRC_IN);
} else {
DrawableCompat.setTint(selectedIndicator, selectedIndicatorPaint.getColor());
}
}
selectedIndicator.draw(canvas);
}
}
可以看出Indicator的宽度只和indicatorLeft,, indicatorRight有关,那个这两个何时赋值呢?
void setIndicatorPosition(int left, int right) {
if (left != indicatorLeft || right != indicatorRight) {
// If the indicator's left/right has changed, invalidate
indicatorLeft = left;
indicatorRight = right;
ViewCompat.postInvalidateOnAnimation(this);
}
}
只要调用这个方法就会赋值,如果我们用反射来设置indicatorLeft和indicatorRight,当TabLayout重新调用setIndicatorPosition的时候又变回去了!除非你能监听到调用这个方法调用的时候再通过反射改变,但是目前我没有找到这个时机,这个时候就得用到AspectJ直接改变代码(反射无法改变代码) 不懂AspectJ可以参考这个学了解一下原理AspectJ基本使用
具体做法
1.依赖
//项目gradle下添加
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
//项目module下添加
apply plugin: 'android-aspectjx'
2.自定义TabLayout
public class IndicatorWidthTabLayout extends TabLayout {
private int indicatorWidth;
public IndicatorWidthTabLayout(Context context) {
super(context);
}
public IndicatorWidthTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initAttrs(context, attrs);
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IndicatorWidthTabLayout);
indicatorWidth = (int) ta.getDimension(R.styleable.IndicatorWidthTabLayout_tab_indicatorWidth, 0);
ta.recycle();
}
public int getIndicatorWidth() {
return indicatorWidth;
}
public void setIndicatorWidth(int indicatorWidth) {
this.indicatorWidth = indicatorWidth;
}
}
3.编写Aspect
@Aspect
public class AopTabLayout {
@Around("execution(* com.google.android.material.tabs.TabLayout.SlidingTabIndicator.setIndicatorPosition(..))")
public void clickFilterHook(ProceedingJoinPoint joinPoint) {
Object child = joinPoint.getThis();
//获取参数,这里就是left,right
Object[] args = joinPoint.getArgs();
if(child instanceof View){
ViewParent parent = ((View) child).getParent();
//判断是不是我们自定义的IndicatorWidthTabLayout
if(parent instanceof IndicatorWidthTabLayout){
int indicatorWidth = ((IndicatorWidthTabLayout) parent).getIndicatorWidth();
//如果我们设置了宽度,就修改left,right
if(indicatorWidth!=0){
if(args!=null){
int indicatorLeft=0;
int indicatorRight=0;
for(int i=0;i<args.length;i++)
{
Object arg = args[i];
Log.e("参数旧"+i+":",""+arg);
if(i==0 &&arg instanceof Integer){
indicatorLeft= (int) arg;
}
if(i==1 &&arg instanceof Integer){
indicatorRight= (int) arg;
}
}
args[0]=(indicatorLeft+indicatorRight-indicatorWidth)/2.0f;
args[1]=(indicatorLeft+indicatorRight+indicatorWidth)/2.0f;
Log.e("参数新:",""+args[0]);
Log.e("参数新:",""+args[1]);
}
}
}
}
try {
if(args!=null){
//执行setIndicatorPosition方法
joinPoint.proceed(args);
}else{
joinPoint.proceed();
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
}
4.使用
<com.example.linqinhui.mvpdemo.aop.IndicatorWidthTabLayout
android:layout_marginTop="10dp"
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tab_indicatorWidth="20dp"
>
现在你想要宽度多大就会多大,完全不需要去自定义一个drawble