引用现成的库实现九宫格拖拽排序功能
This commit is contained in:
@@ -13,11 +13,11 @@ android {
|
||||
applicationId = "com.memory.app"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 76
|
||||
versionName = "1.9.2"
|
||||
versionCode = 87
|
||||
versionName = "2.0.3"
|
||||
|
||||
buildConfigField("String", "API_BASE_URL", "\"https://x.amos.us.kg/api/\"")
|
||||
buildConfigField("int", "VERSION_CODE", "76")
|
||||
buildConfigField("int", "VERSION_CODE", "87")
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@@ -91,6 +91,9 @@ dependencies {
|
||||
// DataStore
|
||||
implementation("androidx.datastore:datastore-preferences:1.1.1")
|
||||
|
||||
// Reorderable - 拖拽排序
|
||||
implementation("sh.calvin.reorderable:reorderable:2.4.0")
|
||||
|
||||
// Debug
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package com.memory.app.ui.components
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.AnimationVector2D
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.VectorConverter
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -22,21 +19,15 @@ import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInParent
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.zIndex
|
||||
import coil.compose.AsyncImage
|
||||
import com.memory.app.ui.theme.Brand500
|
||||
import kotlinx.coroutines.launch
|
||||
import sh.calvin.reorderable.ReorderableItem
|
||||
import sh.calvin.reorderable.rememberReorderableLazyGridState
|
||||
|
||||
sealed class MediaItemData {
|
||||
abstract val id: String
|
||||
@@ -45,7 +36,6 @@ sealed class MediaItemData {
|
||||
data class Video(val uri: Uri, override val id: String = uri.toString()) : MediaItemData()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun ReorderableMediaGrid(
|
||||
items: List<MediaItemData>,
|
||||
@@ -57,12 +47,6 @@ fun ReorderableMediaGrid(
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var mediaItems by remember(items) { mutableStateOf(items) }
|
||||
var draggedIndex by remember { mutableStateOf<Int?>(null) }
|
||||
var draggedItemOffset by remember { mutableStateOf(Offset.Zero) }
|
||||
|
||||
// 记录每个项目的目标位置偏移(用于动画)
|
||||
val itemOffsets = remember { mutableStateMapOf<String, Animatable<Offset, AnimationVector2D>>() }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
// 同步外部变化
|
||||
LaunchedEffect(items) {
|
||||
@@ -74,177 +58,68 @@ fun ReorderableMediaGrid(
|
||||
if (mediaItems.isEmpty()) return
|
||||
|
||||
val columns = if (mediaItems.size <= 3) mediaItems.size else 3
|
||||
val rows = (mediaItems.size + columns - 1) / columns
|
||||
val itemSize = 90.dp
|
||||
val spacing = 8.dp
|
||||
val itemSizePx = itemSize.value + spacing.value
|
||||
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(spacing)
|
||||
) {
|
||||
for (row in 0 until rows) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(spacing)) {
|
||||
for (col in 0 until columns) {
|
||||
val index = row * columns + col
|
||||
if (index < mediaItems.size) {
|
||||
val item = mediaItems[index]
|
||||
val progress = uploadProgress[index]
|
||||
val isDragging = draggedIndex == index
|
||||
|
||||
// 为每个项目创建动画偏移
|
||||
val animatedOffset = itemOffsets.getOrPut(item.id) {
|
||||
Animatable(Offset.Zero, Offset.VectorConverter)
|
||||
val lazyGridState = rememberLazyGridState()
|
||||
val reorderableState = rememberReorderableLazyGridState(lazyGridState) { from, to ->
|
||||
mediaItems = mediaItems.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
onItemsReordered(mediaItems)
|
||||
}
|
||||
|
||||
ReorderableMediaItem(
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(columns),
|
||||
state = lazyGridState,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = modifier
|
||||
.heightIn(max = 300.dp)
|
||||
) {
|
||||
items(mediaItems, key = { it.id }) { item ->
|
||||
ReorderableItem(reorderableState, key = item.id) { isDragging ->
|
||||
val index = mediaItems.indexOf(item)
|
||||
val progress = uploadProgress[index]
|
||||
|
||||
MediaItemCard(
|
||||
item = item,
|
||||
index = index,
|
||||
isDragging = isDragging,
|
||||
dragOffset = if (isDragging) draggedItemOffset else Offset.Zero,
|
||||
animatedOffset = if (!isDragging) animatedOffset.value else Offset.Zero,
|
||||
onRemove = if (!isLoading && onRemove != null) {
|
||||
{ onRemove(item) }
|
||||
} else null,
|
||||
onClick = if (onClick != null) {
|
||||
{ onClick(item) }
|
||||
} else null,
|
||||
onDragStart = {
|
||||
if (!isLoading) {
|
||||
draggedIndex = index
|
||||
draggedItemOffset = Offset.Zero
|
||||
}
|
||||
},
|
||||
onDrag = { offset ->
|
||||
val currentIndex = draggedIndex ?: return@ReorderableMediaItem
|
||||
draggedItemOffset += offset
|
||||
|
||||
// 计算拖拽项当前的行列位置
|
||||
val currentRow = currentIndex / columns
|
||||
val currentCol = currentIndex % columns
|
||||
|
||||
// 直接基于偏移量判断是否应该交换,而不是先计算 targetCol
|
||||
// 这样可以避免刚越过边界就触发交换的问题
|
||||
|
||||
// 计算应该交换到哪个方向
|
||||
val colOffset = when {
|
||||
draggedItemOffset.x > itemSizePx * 0.7f -> 1 // 向右超过 70%
|
||||
draggedItemOffset.x < -itemSizePx * 0.7f -> -1 // 向左超过 70%
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val rowOffset = when {
|
||||
draggedItemOffset.y > itemSizePx * 0.7f -> 1 // 向下超过 70%
|
||||
draggedItemOffset.y < -itemSizePx * 0.7f -> -1 // 向上超过 70%
|
||||
else -> 0
|
||||
}
|
||||
|
||||
// 只有在超过阈值时才计算目标位置
|
||||
if (colOffset != 0 || rowOffset != 0) {
|
||||
val targetCol = currentCol + colOffset
|
||||
val targetRow = currentRow + rowOffset
|
||||
val targetIndex = targetRow * columns + targetCol
|
||||
|
||||
// 检查目标索引是否有效
|
||||
if (targetIndex in mediaItems.indices && targetIndex != currentIndex) {
|
||||
// 交换位置
|
||||
val newList = mediaItems.toMutableList()
|
||||
val draggedItem = newList[currentIndex]
|
||||
val targetItem = newList[targetIndex]
|
||||
|
||||
newList[currentIndex] = targetItem
|
||||
newList[targetIndex] = draggedItem
|
||||
|
||||
// 计算被交换项目需要移动的偏移量
|
||||
val swapOffset = Offset(
|
||||
(currentCol - targetCol) * itemSizePx,
|
||||
(currentRow - targetRow) * itemSizePx
|
||||
)
|
||||
|
||||
// 启动动画 - 使用更慢的动画参数
|
||||
scope.launch {
|
||||
val targetItemAnimatable = itemOffsets.getOrPut(targetItem.id) {
|
||||
Animatable(Offset.Zero, Offset.VectorConverter)
|
||||
}
|
||||
targetItemAnimatable.snapTo(swapOffset)
|
||||
targetItemAnimatable.animateTo(
|
||||
Offset.Zero,
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioLowBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
uploadProgress = progress,
|
||||
modifier = Modifier
|
||||
.aspectRatio(1f)
|
||||
.longPressDraggableHandle(
|
||||
enabled = !isLoading,
|
||||
onDragStarted = {},
|
||||
onDragStopped = {}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
mediaItems = newList
|
||||
onItemsReordered(newList)
|
||||
|
||||
// 更新拖拽索引,重置偏移量为 0
|
||||
// 从新位置重新开始计算,避免连续快速交换
|
||||
draggedIndex = targetIndex
|
||||
draggedItemOffset = Offset.Zero
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragEnd = {
|
||||
draggedIndex = null
|
||||
draggedItemOffset = Offset.Zero
|
||||
},
|
||||
uploadProgress = progress
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ReorderableMediaItem(
|
||||
private fun MediaItemCard(
|
||||
item: MediaItemData,
|
||||
index: Int,
|
||||
isDragging: Boolean,
|
||||
dragOffset: Offset,
|
||||
animatedOffset: Offset,
|
||||
onRemove: (() -> Unit)?,
|
||||
onClick: (() -> Unit)?,
|
||||
onDragStart: () -> Unit,
|
||||
onDrag: (Offset) -> Unit,
|
||||
onDragEnd: () -> Unit,
|
||||
uploadProgress: Float? = null
|
||||
uploadProgress: Float?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// 判断是否正在动画中
|
||||
val isAnimating = animatedOffset != Offset.Zero
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(90.dp)
|
||||
modifier = modifier
|
||||
.graphicsLayer {
|
||||
// 使用 graphicsLayer 进行硬件加速的变换
|
||||
scaleX = if (isDragging) 1.05f else 1f
|
||||
scaleY = if (isDragging) 1.05f else 1f
|
||||
translationX = dragOffset.x + animatedOffset.x
|
||||
translationY = dragOffset.y + animatedOffset.y
|
||||
shadowElevation = if (isDragging) 8.dp.toPx() else 0f
|
||||
}
|
||||
.zIndex(
|
||||
when {
|
||||
isDragging -> 2f // 拖拽项最高层级
|
||||
isAnimating -> 1f // 动画项次高层级,避免被其他项遮挡
|
||||
else -> 0f // 普通项最低层级
|
||||
}
|
||||
)
|
||||
.pointerInput(Unit) {
|
||||
detectDragGesturesAfterLongPress(
|
||||
onDragStart = { onDragStart() },
|
||||
onDrag = { change, dragAmount ->
|
||||
change.consume()
|
||||
onDrag(dragAmount)
|
||||
},
|
||||
onDragEnd = { onDragEnd() },
|
||||
onDragCancel = { onDragEnd() }
|
||||
)
|
||||
}
|
||||
.zIndex(if (isDragging) 1f else 0f)
|
||||
.then(
|
||||
if (onClick != null && uploadProgress == null) {
|
||||
Modifier.clickable { onClick() }
|
||||
|
||||
@@ -15,8 +15,11 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||
import androidx.compose.foundation.gestures.awaitFirstDown
|
||||
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.items
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
|
||||
@@ -61,6 +64,8 @@ import com.memory.app.ui.components.MusicCard
|
||||
import com.memory.app.ui.components.VideoPlayer
|
||||
import com.memory.app.ui.theme.*
|
||||
import kotlinx.coroutines.launch
|
||||
import sh.calvin.reorderable.ReorderableItem
|
||||
import sh.calvin.reorderable.rememberReorderableLazyGridState
|
||||
|
||||
@Composable
|
||||
fun EditPostScreen(
|
||||
@@ -491,7 +496,6 @@ private sealed class EditMediaItem {
|
||||
data class NewVideo(val uri: Uri, override val id: String = uri.toString()) : EditMediaItem()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun EditReorderableMediaGrid(
|
||||
items: List<EditMediaItem>,
|
||||
@@ -502,12 +506,6 @@ private fun EditReorderableMediaGrid(
|
||||
isLoading: Boolean = false
|
||||
) {
|
||||
var mediaItems by remember(items) { mutableStateOf(items) }
|
||||
var draggedIndex by remember { mutableStateOf<Int?>(null) }
|
||||
var draggedItemOffset by remember { mutableStateOf(Offset.Zero) }
|
||||
|
||||
// 记录每个项目的目标位置偏移(用于动画)
|
||||
val itemOffsets = remember { mutableStateMapOf<String, Animatable<Offset, AnimationVector2D>>() }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(items) {
|
||||
if (items != mediaItems) {
|
||||
@@ -518,174 +516,67 @@ private fun EditReorderableMediaGrid(
|
||||
if (mediaItems.isEmpty()) return
|
||||
|
||||
val columns = if (mediaItems.size <= 3) mediaItems.size else 3
|
||||
val rows = (mediaItems.size + columns - 1) / columns
|
||||
val itemSize = 90.dp
|
||||
val spacing = 8.dp
|
||||
val itemSizePx = itemSize.value + spacing.value
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(spacing)) {
|
||||
for (row in 0 until rows) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(spacing)) {
|
||||
for (col in 0 until columns) {
|
||||
val index = row * columns + col
|
||||
if (index < mediaItems.size) {
|
||||
val item = mediaItems[index]
|
||||
val progress = uploadProgress[index]
|
||||
val isDragging = draggedIndex == index
|
||||
|
||||
// 为每个项目创建动画偏移
|
||||
val animatedOffset = itemOffsets.getOrPut(item.id) {
|
||||
Animatable(Offset.Zero, Offset.VectorConverter)
|
||||
val lazyGridState = rememberLazyGridState()
|
||||
val reorderableState = rememberReorderableLazyGridState(lazyGridState) { from, to ->
|
||||
mediaItems = mediaItems.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
onItemsReordered(mediaItems)
|
||||
}
|
||||
|
||||
EditReorderableMediaItem(
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(columns),
|
||||
state = lazyGridState,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.heightIn(max = 300.dp)
|
||||
) {
|
||||
items(mediaItems, key = { it.id }) { item ->
|
||||
ReorderableItem(reorderableState, key = item.id) { isDragging ->
|
||||
val index = mediaItems.indexOf(item)
|
||||
val progress = uploadProgress[index]
|
||||
|
||||
EditMediaItemCard(
|
||||
item = item,
|
||||
index = index,
|
||||
isDragging = isDragging,
|
||||
dragOffset = if (isDragging) draggedItemOffset else Offset.Zero,
|
||||
animatedOffset = if (!isDragging) animatedOffset.value else Offset.Zero,
|
||||
onRemove = if (!isLoading && onRemove != null) {
|
||||
{ onRemove(item) }
|
||||
} else null,
|
||||
onClick = if (onClick != null) {
|
||||
{ onClick(item) }
|
||||
} else null,
|
||||
onDragStart = {
|
||||
if (!isLoading) {
|
||||
draggedIndex = index
|
||||
draggedItemOffset = Offset.Zero
|
||||
}
|
||||
},
|
||||
onDrag = { offset ->
|
||||
val currentIndex = draggedIndex ?: return@EditReorderableMediaItem
|
||||
draggedItemOffset += offset
|
||||
|
||||
// 计算拖拽项当前的行列位置
|
||||
val currentRow = currentIndex / columns
|
||||
val currentCol = currentIndex % columns
|
||||
|
||||
// 直接基于偏移量判断是否应该交换,而不是先计算 targetCol
|
||||
// 这样可以避免刚越过边界就触发交换的问题
|
||||
|
||||
// 计算应该交换到哪个方向
|
||||
val colOffset = when {
|
||||
draggedItemOffset.x > itemSizePx * 0.7f -> 1 // 向右超过 70%
|
||||
draggedItemOffset.x < -itemSizePx * 0.7f -> -1 // 向左超过 70%
|
||||
else -> 0
|
||||
}
|
||||
|
||||
val rowOffset = when {
|
||||
draggedItemOffset.y > itemSizePx * 0.7f -> 1 // 向下超过 70%
|
||||
draggedItemOffset.y < -itemSizePx * 0.7f -> -1 // 向上超过 70%
|
||||
else -> 0
|
||||
}
|
||||
|
||||
// 只有在超过阈值时才计算目标位置
|
||||
if (colOffset != 0 || rowOffset != 0) {
|
||||
val targetCol = currentCol + colOffset
|
||||
val targetRow = currentRow + rowOffset
|
||||
val targetIndex = targetRow * columns + targetCol
|
||||
|
||||
// 检查目标索引是否有效
|
||||
if (targetIndex in mediaItems.indices && targetIndex != currentIndex) {
|
||||
// 交换位置
|
||||
val newList = mediaItems.toMutableList()
|
||||
val draggedItem = newList[currentIndex]
|
||||
val targetItem = newList[targetIndex]
|
||||
|
||||
newList[currentIndex] = targetItem
|
||||
newList[targetIndex] = draggedItem
|
||||
|
||||
// 计算被交换项目需要移动的偏移量
|
||||
val swapOffset = Offset(
|
||||
(currentCol - targetCol) * itemSizePx,
|
||||
(currentRow - targetRow) * itemSizePx
|
||||
)
|
||||
|
||||
// 启动动画 - 使用更慢的动画参数
|
||||
scope.launch {
|
||||
val targetItemAnimatable = itemOffsets.getOrPut(targetItem.id) {
|
||||
Animatable(Offset.Zero, Offset.VectorConverter)
|
||||
}
|
||||
targetItemAnimatable.snapTo(swapOffset)
|
||||
targetItemAnimatable.animateTo(
|
||||
Offset.Zero,
|
||||
animationSpec = spring(
|
||||
dampingRatio = Spring.DampingRatioLowBouncy,
|
||||
stiffness = Spring.StiffnessLow
|
||||
uploadProgress = progress,
|
||||
modifier = Modifier
|
||||
.aspectRatio(1f)
|
||||
.longPressDraggableHandle(
|
||||
enabled = !isLoading,
|
||||
onDragStarted = {},
|
||||
onDragStopped = {}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
mediaItems = newList
|
||||
onItemsReordered(newList)
|
||||
|
||||
// 更新拖拽索引,重置偏移量为 0
|
||||
// 从新位置重新开始计算,避免连续快速交换
|
||||
draggedIndex = targetIndex
|
||||
draggedItemOffset = Offset.Zero
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragEnd = {
|
||||
draggedIndex = null
|
||||
draggedItemOffset = Offset.Zero
|
||||
},
|
||||
uploadProgress = progress
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditReorderableMediaItem(
|
||||
private fun EditMediaItemCard(
|
||||
item: EditMediaItem,
|
||||
index: Int,
|
||||
isDragging: Boolean,
|
||||
dragOffset: Offset,
|
||||
animatedOffset: Offset,
|
||||
onRemove: (() -> Unit)?,
|
||||
onClick: (() -> Unit)?,
|
||||
onDragStart: () -> Unit,
|
||||
onDrag: (Offset) -> Unit,
|
||||
onDragEnd: () -> Unit,
|
||||
uploadProgress: Float? = null
|
||||
uploadProgress: Float?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// 判断是否正在动画中
|
||||
val isAnimating = animatedOffset != Offset.Zero
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(90.dp)
|
||||
modifier = modifier
|
||||
.graphicsLayer {
|
||||
// 使用 graphicsLayer 进行硬件加速的变换
|
||||
scaleX = if (isDragging) 1.05f else 1f
|
||||
scaleY = if (isDragging) 1.05f else 1f
|
||||
translationX = dragOffset.x + animatedOffset.x
|
||||
translationY = dragOffset.y + animatedOffset.y
|
||||
shadowElevation = if (isDragging) 8.dp.toPx() else 0f
|
||||
}
|
||||
.zIndex(
|
||||
when {
|
||||
isDragging -> 2f // 拖拽项最高层级
|
||||
isAnimating -> 1f // 动画项次高层级,避免被其他项遮挡
|
||||
else -> 0f // 普通项最低层级
|
||||
}
|
||||
)
|
||||
.pointerInput(Unit) {
|
||||
detectDragGesturesAfterLongPress(
|
||||
onDragStart = { onDragStart() },
|
||||
onDrag = { change, dragAmount ->
|
||||
change.consume()
|
||||
onDrag(dragAmount)
|
||||
},
|
||||
onDragEnd = { onDragEnd() },
|
||||
onDragCancel = { onDragEnd() }
|
||||
)
|
||||
}
|
||||
.zIndex(if (isDragging) 1f else 0f)
|
||||
.then(
|
||||
if (onClick != null && uploadProgress == null) {
|
||||
Modifier.clickable { onClick() }
|
||||
|
||||
Reference in New Issue
Block a user