其他
利用反编译,仿写一个小红书图片指示器吧
https://juejin.cn/user/2788017218532046
确定向外暴露的方法
初始化方法,设置图片的张数; 图片滑动时更改指示器的方法,传入当前在哪张图片上;
public final void setCount(int i) {
int i2;
if (i <= 1) {
// 猜测是将View隐藏
ViewExtensions.m238052b(this);
return;
}
// 猜测是将View展现
ViewExtensions.m238038p(this);
if (i == this.f67649f) {
m173332c(0);
return;
}
removeAllViews();
this.f67650g.clear();
this.f67647d = 0;
this.f67646c = 0;
this.f67649f = i;
int i3 = this.f67648e;
if (i >= i3) {
i2 = (this.f67644a * i3) + ((i3 - 1) * this.f67645b);
} else {
i2 = ((i - 1) * this.f67645b) + (this.f67644a * i);
}
getLayoutParams().width = i2;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
Objects.requireNonNull(layoutParams, "null cannot be cast to non-null type android.widget.LinearLayout.LayoutParams");
((LinearLayout.LayoutParams) layoutParams).gravity = 1;
for (int i4 = 0; i4 < i; i4++) {
ImageView m173333b = m173333b(i4);
addView(m173333b);
this.f67650g.add(m173333b);
}
Drawable drawable = this.f67650g.get(0).getDrawable();
Objects.requireNonNull(drawable, "null cannot be cast to non-null type android.graphics.drawable.TransitionDrawable");
((TransitionDrawable) drawable).startTransition(0);
int i5 = this.f67648e;
if (i <= i5) {
return;
}
this.f67650g.get(i5 - 1).setScaleX(0.6f);
this.f67650g.get(this.f67648e - 1).setScaleY(0.6f);
}
// 方法2,设置当前所在的位置
public final void setSelectedIndex(int i) {
int i2 = this.f67646c;
if (i != i2) {
boolean z = false;
if (i >= 0 && i < this.f67649f) {
z = true;
}
if (!z) {
return;
}
if (Math.abs(i - i2) > 1) {
m173332c(i);
} else if (this.f67649f <= this.f67648e) {
Drawable drawable = this.f67650g.get(this.f67647d).getDrawable();
Objects.requireNonNull(drawable, "null cannot be cast to non-null type android.graphics.drawable.TransitionDrawable");
((TransitionDrawable) drawable).reverseTransition(200);
Drawable drawable2 = this.f67650g.get(i).getDrawable();
Objects.requireNonNull(drawable2, "null cannot be cast to non-null type android.graphics.drawable.TransitionDrawable");
((TransitionDrawable) drawable2).startTransition(200);
int i3 = this.f67646c;
if (i > i3) {
this.f67646c = i3 + 1;
this.f67647d++;
return;
}
this.f67646c = i3 - 1;
this.f67647d--;
} else if (i > this.f67646c) {
m173330e();
} else {
m173331d();
}
}
}
明确几个成员变量
public int f67644a;
/* renamed from: b */
public int f67645b;
/* renamed from: c */
public int f67646c;
/* renamed from: d */
public int f67647d;
/* renamed from: e */
public final int f67648e;
/* renamed from: f */
public int f67649f;
/* renamed from: g */
public ArrayList<ImageView> f67650g;
/* renamed from: h */
public int f67651h;
/* renamed from: i */
public Map<Integer, View> f67652i;
super(context, attributeSet, i);
Intrinsics.checkNotNullParameter(context, "context");
this.f67652i = new LinkedHashMap();
Resources system = Resources.getSystem();
Intrinsics.checkExpressionValueIsNotNull(system, "Resources.getSystem()");
// 翻译下来就是5dp,应该是圆点的大小
this.f67644a = (int) TypedValue.applyDimension(1, 5, system.getDisplayMetrics());
Resources system2 = Resources.getSystem();
Intrinsics.checkExpressionValueIsNotNull(system2, "Resources.getSystem()");
// 翻译下来是3dp,应该是小圆点的大小或边距
this.f67645b = (int) TypedValue.applyDimension(1, 3, system2.getDisplayMetrics());
// 最多5个圆点
this.f67648e = 5;
this.f67650g = new ArrayList<>();
this.f67651h = R$drawable.red_view_indicator_transition_v2;
}
f67644a:圆点大小,命名为normalSize f67644b:小圆点大小或margin值,命名为smallSize f67648e:最大圆点数,命名为MAX_DOT_SIZE f67650g:圆点ImageView的集合,命名为dotList f67651h:圆点View背景色的Drawable资源,命名为res
setCount方法解析
// 数量小于1,则隐藏View
if (count <= 1) {
visibility = View.GONE
return
}
visibility = View.VISIBLE
// 如果数量一致,则跳转到第一个,因为无需再做重复的事情
if (count == f67646f) {
m17333c(0)
return
}
// 初始化变量
removeAllViews()
dotList.clear()
f67647d = 0;
f67646c = 0;
f67646f = count
// 设置控件的宽度,分超出最多点或最多点以内
val width = if (count >= MAX_DOT_SIZE) {
normalSize * MAX_DOT_SIZE + (MAX_DOT_SIZE - 1) * smallSize
} else {
(count - 1) * smallSize + normalSize * count
}
layoutParams.width = width
// 往ViewGroup中添加View
for (i in 0 until count) {
// 猜测m173333b方法为创建圆点ImageView的方法
val dot = m173333b(i)
addView(dot)
dotList.add(dot)
}
// 设置第一个点位选中态
val drawable = dotList[0].drawable
(drawable as? TransitionDrawable)?.startTransition(0)
// 如果图片数量小于设置的最多的圆点数,则返回,5个以内的话,所有圆点大小一致
if (count <= MAX_DOT_SIZE) return
// 将最后一个点变小
dotList.get(MAX_DOT_SIZE - 1).setScaleX(0.6f);
dotList.get(MAX_DOT_SIZE - 1).setScaleY(0.6f);
}
根据图片数,控制View的显示与否; 初始化变量; 控制只初始化一次; 设置控件的宽度; 往ViewGroup中添加圆点ImageView; 设置第一个点的选中态; 设置最后一个点的大小;
f67646f:图片数,亦是圆点数,重命名为imageSize; f67644b:圆点之间的间距;
setSelectedIndex方法解析
// 如果index跟f67646c相等则返回,猜测f67646c是记录上一次的值
if (index == f67646c) return
// 如果index不在 0和imageSize-1之间,则返回,避免一些数组越界的问题
if (index !in 0 until imageSize) {
return
}
if (abs(index - f67646c) > 1) {
// 非相邻图片的切换的特殊方法
m173332c(index)
} else if (imageSize <= MAX_DOT_SIZE) {
// 图片数在最大圆点数之内的情况,较为简单,仅需要做圆点选中态的切换
val drawable = dotList[m173332d].drawable
(drawable as? TransitionDrawable)?.reverseTransition(200)
val drawable2 = dotList[index].drawable
(drawable2 as? TransitionDrawable)?.startTransition(200)
if (index > realPos) {
m173332d++
m173332c++
return
}
this.m173332c = m173332c - 1
this.m173332d--
} else if (index > m173332c) {
// 向前移动
m173332e()
} else {
// 向后移动
m173332d()
}
}
m173332c:用于非相邻图片之间的切换的特殊方法; m173332e:向前移动的方法,重命名为stepNext; m173332d:向后移动的方法,重命名为stepBack;
// 将上一个点置为非选中态,当前点置为选中态
val drawable = dotList[realPos].drawable
(drawable as? TransitionDrawable)?.reverseTransition(200)
val drawable2 = dotList[realPos - 1].drawable
(drawable2 as? TransitionDrawable)?.startTransition(200)
// 第2个点时,需要做动画
if (f67646d == 1 && realPos != 1) {
m173327h(false)
if (realPos != 2) {
m173329f(realPos - 2)
}
m173329a(realPos - 1)
m173329f(realPos + 2)
} else {
f67646d--
}
realPos--
}
private fun stepNext() {
// 将上一个点置为非选中态,当前点置为选中态
val drawable = dotList[realPos].drawable
(drawable as? TransitionDrawable)?.reverseTransition(200)
val drawable2 = dotList[realPos + 1].drawable
(drawable2 as? TransitionDrawable)?.startTransition(200)
// 第4个点时,需要做动画
val i = f67646d
if (i == 3 && realPos != imageSize - 2) {
m173327h(true)
if (realPos != imageSize - 3) {
m173329f(realPos + 2)
}
m173329a(realPos + 1)
m173329f(realPos - 2)
} else {
f67646d = i + 1
}
realPos++
}
jumpToIndex方法解析
if (index == realPos) return
if (index !in 0 until imageSize) return
var targetTransition = 0
if (imageSize <= MAX_DOT_SIZE) {
// 小于等于最多点的情况,比较简单
curPos = index
} else {
when (index) {
in imageSize - 4 until imageSize -> {
targetTransition = (imageSize - 5) * (normalSize + smallSize)
curPos = index - imageSize + 5
shrinkDot(imageSize - 5)
for (i in imageSize - 4 until imageSize) {
expandDot(i)
}
}
in 2 until imageSize - 4 -> {
val leftIndex = index - 1
targetTransition = (normalSize + smallSize) * leftIndex
this.curPos = 1
shrinkDot(leftIndex)
val rightIndex = index + 3
shrinkDot(rightIndex)
for (i in index until rightIndex) {
expandDot(i)
}
}
in 0..2 -> {
curPos = index
for (i in 0 until (MAX_DOT_SIZE - 1)) {
expandDot(i)
}
shrinkDot(MAX_DOT_SIZE - 1)
targetTransition = 0
}
}
val x = (-targetTransition) - dotList[0].x
for (i in 0 until imageSize) {
val imageView = dotList[i]
imageView.x = imageView.x + x
}
}
val drawable = dotList[realPos].drawable
(drawable as? TransitionDrawable)?.reverseTransition(0)
val drawable2 = dotList[index].drawable
(drawable2 as? TransitionDrawable)?.startTransition(0)
realPos = index
}
有几张图片就有多少个圆点; View的可视区域仅有最多5个点的宽度范围,在切换过程中做平移和圆点放大缩小的动画;
https://github.com/varenyzc/redbook_indicator