/Loading

仿IOS效果的Loading

Primary LanguageKotlin

  • 绘制 利用生命周期控制 转圈圈 和倒计时 还没研究好如何利用动画周期性的驱动绘制,后面再做优化。
@Composable
fun Loading(
    whiteBackground: Boolean = false,
    viewModel: LoadingViewModel = androidx.lifecycle.viewmodel.compose.viewModel(),
    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
) {
    LaunchedEffect(Unit) {
        viewModel.setBackground(whiteBackground)
    }
    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_START -> {
                    viewModel.startTimer(System.currentTimeMillis())
                }
                Lifecycle.Event.ON_STOP -> {
                    viewModel.timerDestroy()
                }
                else -> {}
            }
        }
        // Add the observer to the lifecycle
        lifecycleOwner.lifecycle.addObserver(observer)
        // When the effect leaves the Composition, remove the observer
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }

    val width = LocalConfiguration.current.screenWidthDp
    val count = 8
    val rotateAngle = (360 / count).toDouble()
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        //1284总宽度  菊花宽度:209    17宽 38长     106     17/53  38/53
        Box(
            modifier = Modifier
                .width((width * 0.16f).dp)
                .aspectRatio(1f)
                .background(
                    if (whiteBackground) Color.White else Color.Black,
                    shape = RoundedCornerShape(10.dp)
                ),
            contentAlignment = Alignment.Center
        ) {
            Canvas(
                modifier = Modifier
                    .fillMaxWidth(0.50f)
                    .aspectRatio(1f)
            ) {
                val r = size.width / 2
                //圆弧形的矩形 长度
                val drawWidth = 0.50 * r
                //圆弧形的矩形 宽度
                val strokeWidth = 0.32 * r
                if (viewModel.mTicker.value > 0) {
                    for (index in 1..count) {
                        val startX =
                            (r + (r - drawWidth) * cos(Math.toRadians(rotateAngle * index))).toFloat()
                        val startY =
                            (r - (r - drawWidth) * sin(Math.toRadians(rotateAngle * index))).toFloat()
                        val endX = (r + r * cos(Math.toRadians(rotateAngle * index))).toFloat()
                        val endY = (r - r * sin(Math.toRadians(rotateAngle * index))).toFloat()
                        drawLine(
                            color = viewModel.mColor[index - 1],
                            start = Offset(startX, startY),
                            end = Offset(endX, endY),
                            cap = StrokeCap.Round,
                            strokeWidth = strokeWidth.toFloat(),
                        )
                    }
                }
            }
        }
    }
}
  • ViewModel
class LoadingViewModel : ViewModel() {

    private var mTimer: CountDownTimer? = null

    private val white1 = Color(0xFFCCCCCC)
    private val white2 = Color(0xD6CCCCCC)
    private val white3 = Color(0xB8CCCCCC)
    private val white4 = Color(0x99CCCCCC)
    private val white5 = Color(0x7ACCCCCC)
    private val white6 = Color(0x5CCCCCCC)
    private val white7 = Color(0x3DCCCCCC)
    private val white8 = Color(0x1FCCCCCC)

    private val black1 = Color(0xFF000000)
    private val black2 = Color(0xD6000000)
    private val black3 = Color(0xB8000000)
    private val black4 = Color(0x99000000)
    private val black5 = Color(0x7A000000)
    private val black6 = Color(0x5C000000)
    private val black7 = Color(0x3D000000)
    private val black8 = Color(0x1F000000)


    val mColor = mutableListOf(
        white1,
        white2,
        white3,
        white4,
        white5,
        white6,
        white7,
        white8,
    )

    fun setBackground(whiteBackground: Boolean) {
        if (whiteBackground) {
            mColor[0] = black1
            mColor[1] = black2
            mColor[2] = black3
            mColor[3] = black4
            mColor[4] = black5
            mColor[5] = black6
            mColor[6] = black7
            mColor[7] = black8
        } else {
            mColor[0] = white1
            mColor[1] = white2
            mColor[2] = white3
            mColor[3] = white4
            mColor[4] = white5
            mColor[5] = white6
            mColor[6] = white7
            mColor[7] = white8
        }
    }

    val mTicker = mutableStateOf(0L)

    /**
     * 支付倒计时
     */
    fun startTimer(time: Long) {
        if (mTimer != null) {
            mTimer?.cancel()
            mTimer = null
        }
        mTimer = object : CountDownTimer(time, 100) {
            @SuppressLint("SetTextI18n")
            override fun onTick(millisUntilFinished: Long) {
                val data = mColor.removeAt(mColor.size - 1)
                mColor.add(0, data)
                mTicker.value = System.currentTimeMillis()
            }

            override fun onFinish() {

            }
        }.start()
    }

    fun timerDestroy() {
        mTimer?.cancel()
        mTimer = null
    }
}