Change-Id: Iaf4f80c34914022d79c7e089799fc6dd5554a532pull/2/head
parent
7ac15771b3
commit
2145f6a7cd
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.samples.apps.nowinandroid.core.ui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import androidx.compose.animation.animateColor
|
||||||
|
import androidx.compose.animation.core.Animatable
|
||||||
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.LinearEasing
|
||||||
|
import androidx.compose.animation.core.RepeatMode
|
||||||
|
import androidx.compose.animation.core.StartOffset
|
||||||
|
import androidx.compose.animation.core.animateFloat
|
||||||
|
import androidx.compose.animation.core.infiniteRepeatable
|
||||||
|
import androidx.compose.animation.core.keyframes
|
||||||
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
|
import androidx.compose.ui.graphics.drawscope.rotate
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoadingWheel(
|
||||||
|
contentDesc: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val infiniteTransition = rememberInfiniteTransition()
|
||||||
|
|
||||||
|
// Specifies the float animation for slowly drawing out the lines on entering
|
||||||
|
val floatAnimValues = (0 until NUM_OF_LINES).map { remember { Animatable(1F) } }
|
||||||
|
LaunchedEffect(floatAnimValues) {
|
||||||
|
(0 until NUM_OF_LINES).map { index ->
|
||||||
|
launch {
|
||||||
|
floatAnimValues[index].animateTo(
|
||||||
|
targetValue = 0F,
|
||||||
|
animationSpec = tween(
|
||||||
|
durationMillis = 100,
|
||||||
|
easing = FastOutSlowInEasing,
|
||||||
|
delayMillis = 40 * index
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specifies the rotation animation of the entire Canvas composable
|
||||||
|
val rotationAnim by infiniteTransition.animateFloat(
|
||||||
|
initialValue = 0F,
|
||||||
|
targetValue = 360F,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = tween(durationMillis = ROTATION_TIME, easing = LinearEasing)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Specifies the color animation for the base-to-progress line color change
|
||||||
|
val baseLineColor = MaterialTheme.colorScheme.onBackground
|
||||||
|
val progressLineColor = MaterialTheme.colorScheme.inversePrimary
|
||||||
|
val colorAnimValues = (0 until NUM_OF_LINES).map { index ->
|
||||||
|
infiniteTransition.animateColor(
|
||||||
|
initialValue = baseLineColor,
|
||||||
|
targetValue = baseLineColor,
|
||||||
|
animationSpec = infiniteRepeatable(
|
||||||
|
animation = keyframes {
|
||||||
|
durationMillis = ROTATION_TIME / 2
|
||||||
|
progressLineColor at ROTATION_TIME / NUM_OF_LINES / 2 with LinearEasing
|
||||||
|
baseLineColor at ROTATION_TIME / NUM_OF_LINES with LinearEasing
|
||||||
|
},
|
||||||
|
repeatMode = RepeatMode.Restart,
|
||||||
|
initialStartOffset = StartOffset(ROTATION_TIME / NUM_OF_LINES / 2 * index)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draws out the LoadingWheel Canvas composable and sets the animations
|
||||||
|
Canvas(
|
||||||
|
modifier = modifier
|
||||||
|
.size(48.dp)
|
||||||
|
.padding(8.dp)
|
||||||
|
.graphicsLayer { rotationZ = rotationAnim }
|
||||||
|
.semantics { contentDescription = contentDesc }
|
||||||
|
) {
|
||||||
|
repeat(NUM_OF_LINES) { index ->
|
||||||
|
rotate(degrees = index * 30f) {
|
||||||
|
drawLine(
|
||||||
|
color = colorAnimValues[index].value,
|
||||||
|
// Animates the initially drawn 1 pixel alpha from 0 to 1
|
||||||
|
alpha = if (floatAnimValues[index].value < 1f) 1f else 0f,
|
||||||
|
strokeWidth = 4F,
|
||||||
|
cap = StrokeCap.Round,
|
||||||
|
start = Offset(size.width / 2, size.height / 4),
|
||||||
|
end = Offset(size.width / 2, floatAnimValues[index].value * size.height / 4)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(
|
||||||
|
name = "Loading Wheel Light Preview",
|
||||||
|
uiMode = Configuration.UI_MODE_NIGHT_NO,
|
||||||
|
)
|
||||||
|
@Preview(
|
||||||
|
name = "Loading Wheel Dark Preview",
|
||||||
|
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||||
|
)
|
||||||
|
@Composable
|
||||||
|
fun LoadingWheelPreview() {
|
||||||
|
NiaTheme {
|
||||||
|
Surface {
|
||||||
|
LoadingWheel(contentDesc = "LoadingWheel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val ROTATION_TIME = 12000
|
||||||
|
private const val NUM_OF_LINES = 12
|
Loading…
Reference in new issue