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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
package de.danoeh.antennapod.view;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.core.text.TextUtilsCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import java.util.Locale;
public class PagerIndicatorView extends View {
private final Paint paint = new Paint();
private float position = 0;
private int numPages = 0;
private int disabledPage = -1;
private int circleColor = 0;
private int circleColorHighlight = -1;
private boolean isLocaleRtl = false;
public PagerIndicatorView(Context context) {
super(context);
setup();
}
public PagerIndicatorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setup();
}
public PagerIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setup();
}
private void setup() {
isLocaleRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault())
== ViewCompat.LAYOUT_DIRECTION_RTL;
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
int[] colorAttrs = new int[]{android.R.attr.textColorSecondary};
TypedArray a = getContext().obtainStyledAttributes(colorAttrs);
circleColorHighlight = a.getColor(0, 0xffffffff);
circleColor = (Integer) new ArgbEvaluator().evaluate(0.8f, 0x00ffffff, circleColorHighlight);
a.recycle();
}
/**
* Visual and logical position distinction only happens in RTL locales (e.g. Persian)
* where pages positions are flipped thus it does nothing in LTR locales (e.g. English)
*/
private float logicalPositionToVisual(float position) {
return isLocaleRtl ? numPages - 1 - position : position;
}
public void setViewPager(ViewPager2 pager) {
numPages = pager.getAdapter().getItemCount();
pager.getAdapter().registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
numPages = pager.getAdapter().getItemCount();
invalidate();
}
});
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
PagerIndicatorView.this.position = logicalPositionToVisual(
position + positionOffset);
invalidate();
}
});
}
public void setDisabledPage(int disabledPage) {
this.disabledPage = (int) logicalPositionToVisual(disabledPage);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < numPages; i++) {
if ((int) Math.floor(position) == i) {
// This is the current dot
drawCircle(canvas, i, (float) (1 - (position - Math.floor(position))));
} else if ((int) Math.ceil(position) == i) {
// This is the next dot
drawCircle(canvas, i, (float) (position - Math.floor(position)));
} else {
drawCircle(canvas, i, 0);
}
}
}
private void drawCircle(Canvas canvas, int position, float frac) {
float availableHeight = canvas.getHeight() - getPaddingTop() - getPaddingBottom();
float circleRadiusSmall = availableHeight * 0.26f;
float circleRadiusBig = availableHeight * 0.35f;
float circleRadiusDelta = (circleRadiusBig - circleRadiusSmall);
float start = 0.5f * (canvas.getWidth() - numPages * 1.5f * availableHeight);
paint.setStrokeWidth(availableHeight * 0.3f);
if (position == disabledPage) {
paint.setStyle(Paint.Style.STROKE);
} else {
paint.setStyle(Paint.Style.FILL_AND_STROKE);
}
paint.setColor((Integer) new ArgbEvaluator().evaluate(frac, circleColor, circleColorHighlight));
canvas.drawCircle(start + (position * 1.5f + 0.75f) * availableHeight, 0.5f * availableHeight + getPaddingTop(),
circleRadiusSmall + frac * circleRadiusDelta, paint);
}
}
|