android - Jetpack 用图像奇怪的问题组成动画
问题描述
我看到 Jetpack compose 出现奇怪的图像闪烁问题。这是一个简单的双牌套牌,顶部图像在屏幕外显示动画以显示第二张牌。第二张卡显示正常一秒钟,然后第一张图像在屏幕上闪烁。我尝试过使用 Coil、Fresco 和 Glide,它们的行为方式都相同。
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import coil.compose.rememberImagePainter
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.roundToInt
class MainViewModel : ViewModel() {
var images = MutableLiveData(listOf(
"https://images.pexels.com/photos/212286/pexels-photo-212286.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/163016/crash-test-collision-60-km-h-distraction-163016.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/1366944/pexels-photo-1366944.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/5878501/pexels-photo-5878501.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/3846022/pexels-photo-3846022.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
))
}
class MainActivity : ComponentActivity() {
private val model by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainScreen(model)
}
}
}
@Composable
fun MainScreen(model: MainViewModel) {
val images: List<String> by model.images.observeAsState(listOf())
Box(
modifier = Modifier.fillMaxSize()
) {
images?.take(2).reversed().forEach {
Card(url = it) {
val d = model.images.value?.toMutableList()
d?.let {
it.removeFirst()
model.images.value = it
}
}
}
}
}
@Composable
fun Card(
url: String,
advance: ()-> Unit = {},
){
val coroutineScope = rememberCoroutineScope()
var offsetX = remember(url) { Animatable(0f) }
Box(
modifier = Modifier
.offset { IntOffset(offsetX.value.roundToInt(), 0) }
.fillMaxSize()
.background(color = Color.White)
.clickable {
coroutineScope.launch {
offsetX.animateTo(
targetValue = 3000F
)
}
coroutineScope.launch {
delay(400)
advance()
}
}
) {
Image(
painter = rememberImagePainter(
data = url,
),
contentDescription = null,
modifier = Modifier
.size(400.dp, 400.dp)
)
}
}
如果有人想尝试一下,也可以把它扔到 github 上: https ://github.com/studentjet/learncompose
解决方案
问题是这样的:你有两个卡片视图。删除最上面的卡片后,compose 会重新使用它们并使用新数据更新它们。虽然最上面的卡片加载了第二张图片,但它仍然显示了第一张。
您可以禁用缓存,但在这种情况下,图像仍会闪烁,因为它会首先显示一个空白空间。相反,您需要将第二张卡片的视图重用于第一张卡片。
特别是在这种情况下,key Composable 的用途是:即使顺序发生变化,它也会在重新组合之间重用相同 key 的内容。
val images = remember {
mutableStateListOf(
"https://images.pexels.com/photos/212286/pexels-photo-212286.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/163016/crash-test-collision-60-km-h-distraction-163016.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/1366944/pexels-photo-1366944.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/5878501/pexels-photo-5878501.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
"https://images.pexels.com/photos/3846022/pexels-photo-3846022.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
)
}
Box(
modifier = Modifier.fillMaxSize()
) {
images.take(2).reversed().forEach {
key(it) {
Card(url = it) {
images.add(
images.removeFirst()
)
}
}
}
}
推荐阅读
- linux - 在 Bash 中使用 heredoc 创建新文件
- linux - Ampps 窗口灰显,Ubuntu 18.04 LTS
- groovy - NiFi从PDF提取到文本
- javascript - 使用 Chrome 更新 73.0.3683.75 解决方法从 Content.js 上传文件?
- android - 无法隐藏/删除 Activity 的标题
- phpmyadmin - 在 Mariadb 中声明变量时出错
- matlab - 用于识别多项式曲线的最大峰值(坐标)的 Matlab 代码
- html - 如何在滚动和调整大小时保持分层的绝对 div 对齐和调整大小?
- java - 如果我可以在没有异常的情况下解决问题,我是否应该在 java 中使用异常?
- javascript - 是否可以在不提示“离开此页面”或“留在此页面”选项的情况下防止刷新浏览器?