實際上我什至不確定這是否是時間問題,但讓我們先從代碼開始。
我從我準備一個簡單的資料結構開始,其中包含從到MainActivity的字母AZ
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val model = mutableStateListOf<Char>()
model.addAll(('A'..'Z').toList())
val swipeComplete = {
model.removeFirst()
}
CardStack(elements = model, onSwipeComplete = { swipeComplete() })
}
}
}
我在這里打電話CardStack,如下所示
@Composable
fun CardStack(elements: List<Char>, onSwipeComplete: () -> Unit) {
elements.take(2).reversed().forEachIndexed { _, character ->
Box {
SwipeCard(
character.toString(),
onSwipeComplete = onSwipeComplete
)
}
}
}
刷卡時,我也想查看它下面的卡。因此我只拿兩張最上面的牌并展示它們。然后是它SwipeCard本身。
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SwipeCard(text: String, onSwipeComplete: () -> Unit) {
val color by remember {
val random = Random()
mutableStateOf(Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)))
}
val screenWidth = LocalConfiguration.current.screenWidthDp.dp.value
val screenDensity = LocalConfiguration.current.densityDpi
var offsetXTarget by remember { mutableStateOf(0f) }
var offsetYTarget by remember { mutableStateOf(0f) }
val swipeThreshold = abs(screenWidth * screenDensity / 100)
var dragInProgress by remember {
mutableStateOf(false)
}
val offsetX by animateFloatAsState(
targetValue = offsetXTarget,
animationSpec = tween(
durationMillis = screenDensity / 3,
easing = LinearEasing
),
finishedListener = {
if (!dragInProgress) {
onSwipeComplete()
}
}
)
val offsetY by animateFloatAsState(
targetValue = offsetYTarget,
animationSpec = tween(
durationMillis = screenDensity / 3,
easing = LinearEasing
)
)
val rotationZ = (offsetX / 60).coerceIn(-40f, 40f) * -1
Card(
shape = RoundedCornerShape(20.dp),
elevation = 0.dp,
backgroundColor = color,
modifier = Modifier
.fillMaxSize()
.padding(50.dp)
.graphicsLayer(
translationX = offsetX,
translationY = offsetY,
rotationZ = rotationZ
)
.pointerInput(Unit) {
detectDragGestures(
onDrag = { change, dragAmount ->
dragInProgress = true
change.consumeAllChanges()
offsetXTarget = dragAmount.x
offsetYTarget = dragAmount.y
},
onDragEnd = {
if (abs(offsetX) < swipeThreshold / 20) {
offsetXTarget = 0f
offsetYTarget = 0f
} else {
offsetXTarget = swipeThreshold
offsetYTarget = swipeThreshold
if (offsetX < 0) {
offsetXTarget *= -1
}
}
dragInProgress = false
}
)
}
) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(
text = text,
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 52.sp
),
color = Color.White
)
}
}
}
這是它在行動中的樣子:

幾個關鍵點,讓我們考慮所有字母 from Ato的初始狀態Z:
當我開始拖動帶有字母“A”的卡片時,我可以看到下方帶有字母“B”的卡片。
當拖動動作結束時,字母“A”的卡片將被影片化到左側或右側,具體取決于用戶選擇的哪一側。
影片完成后,onSwipeComplete應呼叫 以洗掉我的資料模型的最頂部元素,即字母“A”。
在從資料模型中洗掉最上面的元素后,我希望將卡片堆重新組合為字母“B”和“C”。
問題是當卡片“A”被激活時,突然在這張影片卡片上繪制了字母“B”,而“B”所在的位置現在變成了“C”。
資料模型似乎已經更新,而第一張帶有字母“A”的卡片仍在影片中消失。
這讓我只剩下一張字母“C”的卡片。“C”下面沒有其他牌。
對我來說,時間似乎有問題,但我無法弄清楚到底是什么。
以下是要添加的所有匯入:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.consumeAllChanges
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.swipecard.ui.theme.SwipeCardTheme
import java.util.*
import kotlin.math.abs
這也需要以下依賴
implementation "androidx.compose.runtime:runtime:1.0.1"
implementation "androidx.compose.runtime:runtime-livedata:1.0.1"
uj5u.com熱心網友回復:
當您從陣列中洗掉一個專案時,從 Compose 的角度來看,它看起來好像您洗掉了最后一個視圖并更改了其他視圖的資料。視圖 A 的視圖被重用于內容 B,并且由于該視圖具有非零偏移值,因此它在螢屏上不可見,因此您只能看到視圖 C。
使用key,您可以告訴 Compose 哪個視圖與哪些資料相關聯,以便正確重用它們:
@Composable
fun CardStack(elements: List<Char>, onSwipeComplete: () -> Unit) {
elements.take(2).reversed().forEach { character ->
key(character) {
SwipeCard(
character.toString(),
onSwipeComplete = onSwipeComplete
)
}
}
}
ps關于您的代碼的一些評論:
screenDensity你傳給是很奇怪的durationMillis。就毫秒而言,它的值非常小,這使您的影片幾乎是即時的,并且在邏輯上看起來有點奇怪。- 如果您不需要 index from
forEachIndexed,只需使用forEach而不是指定_占位符。 - 像你在這里所做的那樣使用
Box,當你只有一個孩子并且沒有指定任何修飾符時Box沒有效果。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/481013.html
