compose loading 第四篇
利用曲线加球体运动径向渐变制作眼睛效果
Box(modifier = Modifier.fillMaxSize()) {
Dialog(
onDismissRequest = { /*TODO*/ },
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
) {
Box(
Modifier
.wrapContentSize()
.defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
.align(
Alignment.Center
)
.background(Color(0x80000000), RoundedCornerShape(12.dp))
) {
var start by remember {
mutableStateOf(false)
}
var start1 by remember {
mutableStateOf(false)
}
val value by animateFloatAsState(
targetValue = if (start1) 1f else 0.0f, animationSpec = spring(
dampingRatio = Spring.DampingRatioLowBouncy,
stiffness = Spring.StiffnessLow
), finishedListener = {
if (it == 1f) {
start1 = false
} else if (it == 0f) {
start1 = true
}
}
)
val key by animateFloatAsState(
targetValue = if (value == 1f) 1f else 0f,
animationSpec = keyframes {
durationMillis = 1000
0.0f at 300 with FastOutLinearInEasing
0.5f at 800 with FastOutSlowInEasing
})
Canvas(modifier = Modifier
.size(48.dp)
.align(Alignment.Center), onDraw = {
var pathIn = Path()//眼白
pathIn.moveTo(size.width, size.height / 2)
pathIn.cubicTo(
size.width,
size.height / 2,
size.width / 2,
(size.height / 2) * (1 - value),
0f,
size.height / 2
)
pathIn.moveTo(size.width, size.height / 2)
pathIn.cubicTo(
size.width,
size.height / 2,
size.width / 2,
size.height / 2 + (size.height / 2) * value,
0f,
size.height / 2
)
drawPath(path = pathIn, Color(0xFF001c3d))
val center = Offset(size.width / 2 - (size.width / 4) * key, size.height / 2)
val r = size.width / 4
drawCircle(//眼球
brush = Brush.radialGradient(
listOf(
Color(0xFF592804),
Color(0xFFa17a74),
), center = center
), radius = r * value
)
drawCircle(
Color(0xFF592804), center = center, radius = 8.dp.value
)
val skinColor = Color(0xFF74bbfb)
val path = Path()
path.moveTo(0f, size.height / 2)
path.cubicTo(
0f,
size.height / 2,
size.width / 2,
-size.height / 2,
size.width,
size.height / 2
)
path.moveTo(size.width, size.height / 2)
path.cubicTo(
size.width,
size.height / 2,
size.width / 2,
(size.height / 2) * (1 - value),
0f,
size.height / 2
)
drawPath(path = path, skinColor)
val pathDown = Path()
pathDown.moveTo(0f, size.height / 2)
pathDown.cubicTo(
0f,
size.height / 2,
size.width / 2,
size.height + size.height / 2,
size.width,
size.height / 2
)
pathDown.moveTo(size.width, size.height / 2)
pathDown.cubicTo(
size.width,
size.height / 2,
size.width / 2,
size.height / 2 + (size.height / 2) * value,
0f,
size.height / 2
)
drawPath(path = pathDown, skinColor)
})
val scope = rememberCoroutineScope()
if (!start) {
LaunchedEffect(key1 = "roll", block = {
scope.launch {
start = true
}
})
} else {
LaunchedEffect(key1 = "roll", block = {
scope.launch {
start1 = true
}
})
}
}
}
}
利用球体环绕制作太阳和月亮环绕
Box(modifier = Modifier.fillMaxSize()) {
Dialog(
onDismissRequest = { /*TODO*/ },
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
) {
Box(
Modifier
.wrapContentSize()
.defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
.align(
Alignment.Center
)
.background(Color(0x80000000), RoundedCornerShape(12.dp))
) {
var start by remember {
mutableStateOf(false)
}
val key by animateFloatAsState(
targetValue = if (start) 2f else 0f,
animationSpec = infiniteRepeatable(
animation = tween(
5000,
easing = LinearEasing
), repeatMode = RepeatMode.Restart
)
)
Canvas(modifier = Modifier
.size(48.dp)
.align(Alignment.Center), onDraw = {
translate(top = size.width / 2) {
drawArc(
color = Color(0xFF4169e1),
startAngle = 180f,
sweepAngle = 180f,
useCenter = true,
style = Fill
)
}
var radius = 30.dp.value
var centerLeft = Offset(0f, size.height / 2)
if (key > 1f) {
rotate(180f * (key - 1), pivot = center) {
drawCircle(
Color.White,
radius = radius / 2,
center = centerLeft,
)
}
} else {
rotate(180f * key, pivot = center) {
drawCircle(
Brush.radialGradient(
listOf(
Color(0xFFff4500),
Color(0xFFff4500),
Color.Transparent
),
center = centerLeft, radius = radius
),
radius = radius,
center = centerLeft,
)
}
}
})
val scope = rememberCoroutineScope()
if (!start) {
LaunchedEffect(key1 = "roll", block = {
scope.launch {
start = true
}
})
}
}
}
}
利用曲线加旋转制作风车
Box(modifier = Modifier.fillMaxSize()) {
Dialog(
onDismissRequest = { /*TODO*/ },
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
) {
Box(
Modifier
.wrapContentSize()
.defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
.align(
Alignment.Center
)
.background(Color(0x80000000), RoundedCornerShape(12.dp))
) {
var start by remember {
mutableStateOf(false)
}
val key by animateFloatAsState(
targetValue = if (start) 1f else 0f,
animationSpec = infiniteRepeatable(
animation = tween(
2000,
easing = FastOutSlowInEasing
), repeatMode = RepeatMode.Restart
)
)
Canvas(modifier = Modifier
.size(48.dp)
.align(Alignment.Center), onDraw = {//风车
drawLine(
Color.Yellow,
start = center,
end = Offset(size.width / 2, size.height),
strokeWidth = 10.dp.value
)
rotate(360 * key, pivot = center) {
for (i in 0 until 2) {
rotate(90f * i, pivot = center) {
val path = Path()
path.moveTo(0f, size.height / 2)
path.cubicTo(
0f,
size.height / 2,
size.width / 4,
size.height / 4,
size.width / 2,
size.height / 2
)
path.quadraticBezierTo(
size.width * 3 / 4,
size.height * 3 / 4,
size.width,
size.height / 2
)
path.lineTo(0f, size.height / 2)
drawPath(path = path, Color.White)
}
}
}
})
val scope = rememberCoroutineScope()
if (!start) {
LaunchedEffect(key1 = "roll", block = {
scope.launch {
start = true
}
})
}
}
}
}
利用曲线加球体误打误撞做的兔头
Box(modifier = Modifier.fillMaxSize()) {
Dialog(
onDismissRequest = { /*TODO*/ },
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
) {
Box(
Modifier
.wrapContentSize()
.defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
.align(
Alignment.Center
)
.background(Color(0x80000000), RoundedCornerShape(12.dp))
) {
var start by remember {
mutableStateOf(false)
}
val keyMul by animateFloatAsState(
targetValue = if (start) 1.5f else 0f,
animationSpec = infiniteRepeatable(
animation = tween(
2000,
easing = FastOutSlowInEasing
), repeatMode = RepeatMode.Restart
)
)
val transY by animateFloatAsState(
targetValue = if (keyMul >= 1f) 1f else 0f,
spring(
dampingRatio = Spring.DampingRatioHighBouncy,
stiffness = Spring.StiffnessHigh
)
)
Canvas(modifier = Modifier
.size(48.dp)
.align(Alignment.Center), onDraw = {
val radius = 24.dp.value
val key = if (keyMul >= 1f) 1f else keyMul
scale(1 - key, pivot = Offset(size.width / 2, 0f)) {
drawCircle(
Color.White,
radius = radius,
center = Offset(size.width / 2, 0f)
)
}
translate(top = size.height * key) {
drawCircle(
Color.White,
radius = radius,
center = Offset(size.width / 2, 0f)
)
}
val path = Path()
val space = sin(45f) * radius
val centerY = size.height * key + radius
val topY = transY * centerY
path.moveTo(size.width / 2, topY)
path.cubicTo(
size.width / 2,
0f,
size.width / 2 - space / 2, centerY - space * 2,
size.width / 2 - space,
centerY - space
)
path.lineTo(size.width / 2, centerY)
path.lineTo(size.width / 2, topY)
path.close()
path.moveTo(size.width / 2, topY)
path.cubicTo(
size.width / 2,
0f,
size.width / 2 + space / 2, centerY - space * 2,
size.width / 2 + space,
centerY - space
)
path.lineTo(size.width / 2, centerY)
path.lineTo(size.width / 2, topY)
drawPath(path = path, Color.White)
})
val scope = rememberCoroutineScope()
if (!start) {
LaunchedEffect(key1 = "roll", block = {
scope.launch {
start = true
}
})
}
}
}
}
模仿不到位的水滴
Box(modifier = Modifier.fillMaxSize()) {
Dialog(
onDismissRequest = { /*TODO*/ },
properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = true)
) {
Box(
Modifier
.wrapContentSize()
.defaultMinSize(minWidth = 120.dp, minHeight = 120.dp)
.align(
Alignment.Center
)
.background(Color(0x80000000), RoundedCornerShape(12.dp))
) {
var start by remember {
mutableStateOf(false)
}
val key by animateFloatAsState(
targetValue = if (start) 1f else 0f,
animationSpec = infiniteRepeatable(
animation = tween(
2000,
easing = FastOutSlowInEasing
), repeatMode = RepeatMode.Restart
)
)
val transY by animateFloatAsState(
targetValue = if (key >= 0.8f) 1f else 0f,
spring(
dampingRatio = Spring.DampingRatioNoBouncy,
stiffness = Spring.StiffnessHigh
)
)
Canvas(modifier = Modifier
.size(48.dp)
.align(Alignment.Center), onDraw = {
val radius = 24.dp.value
val color = Color(0xFF4169e1)
scale(
1 - key,
pivot = Offset(size.width / 2, 0f)
) {
drawCircle(
color,
radius = radius,
center = Offset(size.width / 2, 0f),
alpha = if (key >= 0.8f) 0f else 1f
)
}
translate(top = size.height * (if (transY == 1f) 1f else key)) {
drawCircle(
color,
radius = radius,
center = Offset(size.width / 2, 0f)
)
}
if (key >= 0.2f) {
val path = Path()
val space = sin(45f) * radius
val centerY = (size.height + radius) * (if (transY == 1f) 1f else key)
val topY = size.height * transY
val bottomY = centerY - space
val topSecondY = centerY - space * 2
path.moveTo(size.width / 2, topY)
path.cubicTo(
size.width / 2,
topY,
size.width / 2 - space / 2, topSecondY,
size.width / 2 - space,
bottomY
)
path.lineTo(size.width / 2, bottomY)
path.lineTo(size.width / 2, topY)
path.close()
path.moveTo(size.width / 2, topY)
path.cubicTo(
size.width / 2,
topY,
size.width / 2 + space / 2, topSecondY,
size.width / 2 + space,
bottomY
)
path.lineTo(size.width / 2, bottomY)
path.lineTo(size.width / 2, topY)
drawPath(path = path, color)
}
})
val scope = rememberCoroutineScope()
if (!start) {
LaunchedEffect(key1 = "roll", block = {
scope.launch {
start = true
}
})
}
}
}
}