繁体   English   中英

如何使用 Animatable 为 Rect position 设置动画?

[英]How to animate Rect position with Animatable?

我正在构建一个图像裁剪器。 我正在使用矩形来绘制动态覆盖。 当覆盖超出图像边界时,当指针向上时,我将其移回图像边界。

我建造的

在此处输入图像描述

open var overlayRect: Rect =
    Rect(offset = Offset.Zero, size = Size(size.width.toFloat(), size.height.toFloat()))

我得到最终的 position 使用这个 function 移回有效范围

internal fun moveIntoBounds(rectBounds: Rect, rectCurrent: Rect): Rect {
    var width = rectCurrent.width
    var height = rectCurrent.height


    if (width > rectBounds.width) {
        width = rectBounds.width
    }

    if (height > rectBounds.height) {
        height = rectBounds.height
    }

    var rect = Rect(offset = rectCurrent.topLeft, size = Size(width, height))

    if (rect.left < rectBounds.left) {
        rect = rect.translate(rectBounds.left - rect.left, 0f)
    }

    if (rect.top < rectBounds.top) {
        rect = rect.translate(0f, rectBounds.top - rect.top)
    }

    if (rect.right > rectBounds.right) {
        rect = rect.translate(rectBounds.right - rect.right, 0f)
    }

    if (rect.bottom > rectBounds.bottom) {
        rect = rect.translate(0f, rectBounds.bottom - rect.bottom)
    }

    return rect
}

并将其设置为指针

override fun onUp(change: PointerInputChange) {
    touchRegion = TouchRegion.None

    overlayRect = moveIntoBounds(rectBounds, overlayRect)

    // Calculate crop rectangle
    cropRect = calculateRectBounds()
    rectTemp = overlayRect.copy()
}

如何将这个矩形动画化到有效边界? 有没有办法使用 Animatable 为矩形设置动画?

我检查了 animation 的官方文档,并建议使用从一个state到另一个DynamicCropStatetransition和转换。在此处扩展 class ,如缩放 state 需要使用 Animatable 或 non-Composable api 进行动画处理。

我解决了这个问题,创建了一个在FloatRect之间转换的AnimationVector4D

val RectToVector = TwoWayConverter(
    convertToVector = { rect: Rect ->
        AnimationVector4D(rect.left, rect.top, rect.width, rect.height)
    },
    convertFromVector = { vector: AnimationVector4D ->
        Rect(
            offset = Offset(vector.v1, vector.v2),
            size = Size(vector.v3, vector.v4)
        )
    }
)

为了演示,创建了一个 class 以在内部进行动画处理并返回Rect的当前值

class RectWrapper {

    private val animatableRect = Animatable(
        Rect(
            offset = Offset.Zero,
            size = Size(300f, 300f)
        ),
        RectToVector
    )

    val rect: Rect
        get() = animatableRect.value

    suspend fun animateRectTo(rect: Rect) {
        animatableRect.animateTo(rect)
    }
}

以及演示如何使用它

@Composable
private fun AnimateRectWithAnimatable() {
    val coroutineScope = rememberCoroutineScope()


    val rectWrapper = remember {
        RectWrapper()
    }

    Column(modifier = Modifier.fillMaxSize()) {

        Button(
            modifier = Modifier
                .padding(10.dp)
                .fillMaxWidth(),
            onClick = {
                coroutineScope.launch {
                    rectWrapper.animateRectTo(
                        Rect(
                            topLeft = Offset(200f, 200f),
                            bottomRight = Offset(800f, 800f)
                        )
                    )
                }
            }
        ) {
            Text("Animate")
        }

        Canvas(
            modifier = Modifier
                .fillMaxSize()
        ) {
            drawRect(
                color = Color.Red,
                topLeft = rectWrapper.rect.topLeft,
                size = rectWrapper.rect.size
            )

        }
    }
}

如果您希望从 class 为Rect设置动画,您可以按上述方式实现它。 我通常将这些类作为State传递给修饰符,并观察并触发Modifier.composed内部的更改,并将结果返回给使用该修饰符的任何 class。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM