foreword
First of all, let's take a look at the loading animation in Xiaomi. Although it's just a picture, because it can't record all of it, many of them are successful as soon as they are loaded, and they don't give me any chance, so I just Taking a screenshot, the feature of his loading animation is that the circle on the left will keep turning.
The imitation effect is as follows:
Implementation process
This is not difficult, just learn a formula, that is, know the center, radius, angle, and find the coordinates of the point on the circle. The calculated result can draw a solid circle at this point. The following is a custom Dialog, let it In the bottom reality, the View is also a custom one.
class MiuiLoadingDialog(context: Context) : Dialog(context) {
private var miuiLoadingView : MiuiLoadingView= MiuiLoadingView(context);
init {
setContentView(miuiLoadingView)
setCancelable(false)
}
override fun show() {
super.show()
val window: Window? = getWindow();
val wlp = window!!.attributes
wlp.gravity = Gravity.BOTTOM
window.setBackgroundDrawable( ColorDrawable(Color.TRANSPARENT));
wlp.width=WindowManager.LayoutParams.MATCH_PARENT;
window.attributes = wlp
}
}
复制代码
The following is the main logic. Inside, first clipPath
cut out a shape with rounded corners through the method, and then draw an outer circle, which is fixed.
The circle in the middle requires a formula, as follows.
x1 = x0 + r * cos(a * PI /180 )
y1 = y0 + r * sin(a * PI /180 )
复制代码
x0 and y0 are the center points of the outer big circle, r is the size of the small circle in the middle, and a is the angle. You only need to keep changing this angle, and the obtained x1 and y1 can be drawn by drawCircle.
class MiuiLoadingView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
//Dialog上面圆角大小
val CIRCULAR: Float = 60f;
//中心移动圆位置
var rx: Float = 0f;
var ry: Float = 0f;
//左边距离
var MARGIN_LEFT: Int = 100;
//中心圆大小
var centerRadiusSize: Float = 7f;
var textPaint: Paint = Paint().apply {
textSize = 50f
color = Color.BLACK
}
var circlePaint: Paint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = 8f
isAntiAlias = true
color = Color.BLACK
}
var centerCirclePaint: Paint = Paint().apply {
style = Paint.Style.FILL
isAntiAlias = true
color = Color.BLACK
}
var degrees = 360;
val TEXT = "正在加载中,请稍等";
var textHeight = 0;
init {
var runnable = object : Runnable {
override fun run() {
val r = 12;
rx = MARGIN_LEFT + r * Math.cos(degrees.toDouble() * Math.PI / 180).toFloat()
ry =
((measuredHeight.toFloat() / 2) + r * Math.sin(degrees.toDouble() * Math.PI / 180)).toFloat();
invalidate()
degrees += 5
if (degrees > 360) degrees = 0
postDelayed(this, 1)
}
}
postDelayed(runnable, 0)
var rect = Rect()
textPaint.getTextBounds(TEXT, 0, TEXT.length, rect)
textHeight = rect.height()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(widthMeasureSpec, 220);
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
var path = Path()
path.addRoundRect(
RectF(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat()),
floatArrayOf(CIRCULAR, CIRCULAR, CIRCULAR, CIRCULAR, 0f, 0f, 0f, 0f), Path.Direction.CW
);
canvas.clipPath(path)
canvas.drawColor(Color.WHITE)
canvas.drawCircle(
MARGIN_LEFT.toFloat(), measuredHeight.toFloat() / 2,
35f, circlePaint
)
canvas.drawCircle(
rx, ry,
centerRadiusSize, centerCirclePaint
)
canvas.drawText(TEXT, (MARGIN_LEFT + 80).toFloat(), ((measuredHeight / 2)+(textHeight/2)).toFloat(), textPaint)
}
}
复制代码