首页动画完成
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.aiosman.riderpro.ui.login
|
package com.aiosman.riderpro.ui.login
|
||||||
|
|
||||||
import android.content.ContentValues.TAG
|
import android.content.ContentValues.TAG
|
||||||
|
import android.content.res.Resources
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.animation.core.LinearEasing
|
import androidx.compose.animation.core.LinearEasing
|
||||||
@@ -9,6 +10,10 @@ import androidx.compose.animation.core.infiniteRepeatable
|
|||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.rememberScrollableState
|
||||||
|
import androidx.compose.foundation.gestures.scrollable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -23,7 +28,9 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -145,11 +152,13 @@ fun LoginPage() {
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.offset(
|
// .offset(
|
||||||
y = (-72).dp
|
// y = (-72).dp
|
||||||
),
|
// ),
|
||||||
) {
|
) {
|
||||||
MovingImageWall()
|
val context = LocalContext.current // 获取 Context
|
||||||
|
MovingImageWall(context.resources) // 将 resources 传递给 MovingImageWall
|
||||||
|
// MovingImageWall()
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -233,14 +242,18 @@ fun LoginPage() {
|
|||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MovingImageWall() {
|
fun MovingImageWall(resources: Resources) {
|
||||||
val imageList1 = remember { mutableStateListOf(R.drawable.wall_1_1, R.drawable.wall_1_2, R.drawable.wall_1_3) }
|
val imageList1 = remember { mutableStateListOf(R.drawable.wall_1_1, R.drawable.wall_1_2, R.drawable.wall_1_3,R.drawable.wall_1_1, R.drawable.wall_1_2, R.drawable.wall_1_3) }
|
||||||
val imageList2 = remember { mutableStateListOf(R.drawable.wall_2_1, R.drawable.wall_2_2, R.drawable.wall_2_3) }
|
val imageList2 = remember { mutableStateListOf(R.drawable.wall_2_1, R.drawable.wall_2_2, R.drawable.wall_2_3,R.drawable.wall_2_1, R.drawable.wall_2_2, R.drawable.wall_2_3) }
|
||||||
val imageList3 = remember { mutableStateListOf(R.drawable.wall_3_1, R.drawable.wall_3_2, R.drawable.wall_3_3) }
|
val imageList3 = remember { mutableStateListOf(R.drawable.wall_3_1, R.drawable.wall_3_2, R.drawable.wall_3_3,R.drawable.wall_3_1, R.drawable.wall_3_2, R.drawable.wall_3_3) }
|
||||||
|
|
||||||
var offset1 by remember { mutableFloatStateOf(0f) }
|
val density = resources.displayMetrics.density // 获取屏幕密度
|
||||||
|
val imageHeight = 208.dp
|
||||||
|
val imageHeightPx = imageHeight.value * density // 将 dp 转换为像素
|
||||||
|
val resetThreshold = imageHeightPx
|
||||||
|
var offset1 by remember { mutableFloatStateOf( -resetThreshold * 3) }
|
||||||
var offset2 by remember { mutableFloatStateOf(0f) }
|
var offset2 by remember { mutableFloatStateOf(0f) }
|
||||||
var offset3 by remember { mutableFloatStateOf(0f) }
|
var offset3 by remember { mutableFloatStateOf( -resetThreshold * 3) }
|
||||||
|
|
||||||
val lifecycleOwner = LocalLifecycleOwner.current
|
val lifecycleOwner = LocalLifecycleOwner.current
|
||||||
val coroutineScope = rememberCoroutineScope() // 使用 rememberCoroutineScope
|
val coroutineScope = rememberCoroutineScope() // 使用 rememberCoroutineScope
|
||||||
@@ -250,13 +263,13 @@ fun MovingImageWall() {
|
|||||||
when (event) {
|
when (event) {
|
||||||
Lifecycle.Event.ON_RESUME -> {
|
Lifecycle.Event.ON_RESUME -> {
|
||||||
coroutineScope.launch { // 在 coroutineScope 中启动协程
|
coroutineScope.launch { // 在 coroutineScope 中启动协程
|
||||||
animateImageWall(imageList1, offset1, speed = 1f) { offset1 = it }
|
animateImageWall(imageList1, offset1, speed = 1f, resources = resources) { offset1 = it }
|
||||||
}
|
}
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
animateImageWall(imageList2, offset2, speed = 1.5f, reverse = true) { offset2 = it }
|
animateImageWall(imageList2, offset2, speed = 1.5f, reverse = true, resources = resources) { offset2 = it }
|
||||||
}
|
}
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
animateImageWall(imageList3, offset3, speed = 2f) { offset3 = it }
|
animateImageWall(imageList3, offset3, speed = 2f, resources = resources) { offset3 = it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Lifecycle.Event.ON_PAUSE -> {
|
Lifecycle.Event.ON_PAUSE -> {
|
||||||
@@ -271,27 +284,53 @@ fun MovingImageWall() {
|
|||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
|
||||||
.offset(y = (-72).dp)
|
|
||||||
) {
|
|
||||||
|
|
||||||
Row (modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(700.dp)){
|
// .height(5000.dp)
|
||||||
|
// .offset(y = (-72).dp)
|
||||||
|
) {
|
||||||
|
val scrollState1 = rememberScrollState()
|
||||||
|
val scrollableState1 = rememberScrollableState { delta ->
|
||||||
|
// 消耗所有滚动事件,阻止用户滚动
|
||||||
|
delta
|
||||||
|
}
|
||||||
|
val scrollState2 = rememberScrollState()
|
||||||
|
val scrollableState2 = rememberScrollableState { delta ->
|
||||||
|
// 消耗所有滚动事件,阻止用户滚动
|
||||||
|
delta
|
||||||
|
}
|
||||||
|
val scrollState3 = rememberScrollState()
|
||||||
|
val scrollableState3 = rememberScrollableState { delta ->
|
||||||
|
// 消耗所有滚动事件,阻止用户滚动
|
||||||
|
delta
|
||||||
|
}
|
||||||
|
Row (modifier = Modifier
|
||||||
|
.fillMaxWidth()){
|
||||||
// 第1列
|
// 第1列
|
||||||
ImageColumn(imageList1, offset1,
|
ImageColumn(imageList1, offset1,
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxHeight()
|
.verticalScroll(scrollState1)
|
||||||
|
.scrollable(
|
||||||
|
state = scrollableState1,
|
||||||
|
orientation = Orientation.Vertical
|
||||||
|
)
|
||||||
.weight(1f))
|
.weight(1f))
|
||||||
// 第2列
|
// 第2列
|
||||||
ImageColumn(imageList2, offset2,
|
ImageColumn(imageList2, offset2,
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxHeight()
|
.verticalScroll(scrollState2)
|
||||||
|
.scrollable(
|
||||||
|
state = scrollableState2,
|
||||||
|
orientation = Orientation.Vertical
|
||||||
|
)
|
||||||
.weight(1f), reverse = true)
|
.weight(1f), reverse = true)
|
||||||
// 第3列
|
// 第3列
|
||||||
ImageColumn(imageList3, offset3,
|
ImageColumn(imageList3, offset3,
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxHeight()
|
.verticalScroll(scrollState3)
|
||||||
|
.scrollable(
|
||||||
|
state = scrollableState3,
|
||||||
|
orientation = Orientation.Vertical
|
||||||
|
)
|
||||||
.weight(1f))
|
.weight(1f))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,11 +385,11 @@ fun ImageColumn(
|
|||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
// 检查是否超出屏幕范围
|
// 检查是否超出屏幕范围
|
||||||
if (translation < -imageHeight.value) { // 移出屏幕底部
|
// if (translation < -imageHeight.value * 3) { // 移出屏幕底部
|
||||||
translation += totalHeight
|
//// translation += (imageHeight.value * 3)
|
||||||
} else if (translation > totalHeight) { // 移出屏幕顶部
|
// } else if (translation > (totalHeight / 2)) { // 移出屏幕顶部
|
||||||
translation -= totalHeight
|
// translation -= (totalHeight / 2)
|
||||||
}
|
// }
|
||||||
translationY = translation
|
translationY = translation
|
||||||
}
|
}
|
||||||
.clip(RoundedCornerShape(16.dp)),
|
.clip(RoundedCornerShape(16.dp)),
|
||||||
@@ -370,68 +409,43 @@ fun ImageColumn(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun animateImageWall(
|
suspend fun animateImageWall(
|
||||||
imageList: MutableList<Int>,
|
imageList: MutableList<Int>,
|
||||||
initialOffset: Float,
|
initialOffset: Float,
|
||||||
speed: Float,
|
speed: Float, // speed 现在以像素为单位
|
||||||
reverse: Boolean = false,
|
reverse: Boolean = false,
|
||||||
|
resources: Resources, // 添加 resources 参数
|
||||||
onUpdate: (Float) -> Unit,
|
onUpdate: (Float) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val density = resources.displayMetrics.density // 获取屏幕密度
|
||||||
var currentOffset = initialOffset
|
var currentOffset = initialOffset
|
||||||
val imageCount = imageList.size
|
val imageCount = imageList.size
|
||||||
val imageHeight = 208.dp
|
val imageHeight = 208.dp
|
||||||
var currentIndex = 0 // 添加一个变量来跟踪当前显示的图片索引
|
val imageHeightPx = imageHeight.value * density // 将 dp 转换为像素
|
||||||
|
val resetThreshold = imageHeightPx
|
||||||
|
Log.d(TAG, "speed: $speed")
|
||||||
|
Log.d(TAG, "resetThreshold: $resetThreshold")
|
||||||
while (true) {
|
while (true) {
|
||||||
onUpdate(currentOffset)
|
onUpdate(currentOffset)
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
currentOffset -= speed
|
currentOffset -= speed
|
||||||
if (currentOffset < -imageHeight.value * (imageCount - 1)) {
|
// Log.d(TAG, "currentOffset: $currentOffset")
|
||||||
// val firstImage = imageList.first() // 将第一个元素移除
|
if (currentOffset <= -resetThreshold * 3) { // 检查是否向上超出阈值
|
||||||
// imageList.add(firstImage) // 将第一个元素添加到末尾
|
// 使用 imageHeightPx 进行计算
|
||||||
currentOffset += imageHeight.value * imageCount // 将图片移动到末尾
|
// 复位
|
||||||
// currentIndex = (currentIndex - 1 + imageCount) % imageCount // 反向旋转
|
currentOffset = initialOffset
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
currentOffset += speed
|
currentOffset += speed
|
||||||
if (currentOffset > imageHeight.value * (imageCount - 1)) {
|
|
||||||
// val lastImage = imageList.last() // 将最后一个元素移除
|
if (currentOffset >= 0) { // 检查是否向上超出阈值
|
||||||
// imageList.add(0, lastImage) // 将最后一个元素添加到开头
|
Log.d(TAG, "currentOffset: $currentOffset")
|
||||||
currentOffset -= imageHeight.value * imageCount // 将图片移动到开头
|
// 使用 imageHeightPx 进行计算
|
||||||
// currentIndex = (currentIndex + 1) % imageCount // 正向旋转
|
// 复位
|
||||||
|
currentOffset = initialOffset
|
||||||
}
|
}
|
||||||
|
// 使用 imageHeightPx 进行计算
|
||||||
}
|
}
|
||||||
// 更新 ImageColumn 中的 currentImage
|
|
||||||
// onUpdate(currentIndex.toFloat()) // 将当前索引传递给 onUpdate
|
|
||||||
delay(16)
|
delay(16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算图片的透明度
|
|
||||||
private fun calculateAlpha(
|
|
||||||
offset: Float,
|
|
||||||
index: Int,
|
|
||||||
imageHeight: Float,
|
|
||||||
totalHeight: Float,
|
|
||||||
reverse: Boolean
|
|
||||||
): Float {
|
|
||||||
val offsetDp = if (reverse) {
|
|
||||||
-offset
|
|
||||||
} else {
|
|
||||||
offset
|
|
||||||
}
|
|
||||||
val imageTop = index * imageHeight
|
|
||||||
val imageBottom = imageTop + imageHeight
|
|
||||||
return when {
|
|
||||||
offsetDp in imageTop..imageBottom -> {
|
|
||||||
(offsetDp - imageTop) / imageHeight
|
|
||||||
}
|
|
||||||
(offsetDp + totalHeight) in imageTop..imageBottom -> { // 考虑循环滚动的情况
|
|
||||||
(offsetDp + totalHeight - imageTop) / imageHeight
|
|
||||||
}
|
|
||||||
(offsetDp - totalHeight) in imageTop..imageBottom -> { // 考虑循环滚动的情况
|
|
||||||
(offsetDp - totalHeight - imageTop) / imageHeight
|
|
||||||
}
|
|
||||||
else -> 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user