components: ReorderableColumn drag shadow follows the card
This commit is contained in:
+25
-3
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -21,10 +20,18 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.geometry.translate
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -53,7 +60,8 @@ private val RowGap: Dp = 2.dp
|
||||
* [GroupedRow]'s card shaping — pass `gapBelow = false` there, this owns spacing)
|
||||
* and a `dragHandle` [Modifier] to attach to the element that starts a drag.
|
||||
* Pass [rowHeight] matching the rows' non-reorder `minHeight`, so they keep their
|
||||
* size when a screen switches into reordering.
|
||||
* size when a screen switches into reordering. [rowInset] is the card's horizontal
|
||||
* inset inside its slot, so the held row's shadow hugs the card, not the slot.
|
||||
*/
|
||||
@Composable
|
||||
fun <T> ReorderableColumn(
|
||||
@@ -62,6 +70,7 @@ fun <T> ReorderableColumn(
|
||||
onReorder: (List<T>) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
rowHeight: Dp = ReorderableRowHeight,
|
||||
rowInset: Dp = GroupedListInset,
|
||||
rowContent: @Composable (item: T, position: Position, dragHandle: Modifier, isDragging: Boolean) -> Unit,
|
||||
) {
|
||||
val pitchPx = with(LocalDensity.current) { (rowHeight + RowGap).toPx() }
|
||||
@@ -174,7 +183,7 @@ fun <T> ReorderableColumn(
|
||||
scaleX = 1.02f
|
||||
scaleY = 1.02f
|
||||
shadowElevation = 8.dp.toPx()
|
||||
shape = RoundedCornerShape(20.dp)
|
||||
shape = InsetShape(groupedShape(positionOf(index, order.size), 22.dp, 6.dp), rowInset)
|
||||
clip = false
|
||||
}
|
||||
},
|
||||
@@ -184,3 +193,16 @@ fun <T> ReorderableColumn(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** [base] laid out [inset] in from both sides of the slot. */
|
||||
private class InsetShape(private val base: Shape, private val inset: Dp) : Shape {
|
||||
override fun createOutline(size: Size, layoutDirection: LayoutDirection, density: Density): Outline {
|
||||
val dx = with(density) { inset.toPx() }
|
||||
val inner = Size((size.width - 2 * dx).coerceAtLeast(0f), size.height)
|
||||
return when (val outline = base.createOutline(inner, layoutDirection, density)) {
|
||||
is Outline.Rectangle -> Outline.Rectangle(outline.rect.translate(Offset(dx, 0f)))
|
||||
is Outline.Rounded -> Outline.Rounded(outline.roundRect.translate(Offset(dx, 0f)))
|
||||
is Outline.Generic -> Outline.Generic(Path().apply { addPath(outline.path, Offset(dx, 0f)) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user