将图像缩放到 JetpackCompose HorizontalPager 的边界之外

问题描述 投票:0回答:1

我正在尝试使用

PointerEvent
(2 个手指)实现缩放图像,当包裹在
Column
中时,它工作得很好(缩小列边界,即屏幕高度的 0.4%),但它没有按预期工作如果它包装在 HorizontalPager 中。 Original image

Column
实现的屏幕截图代码:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ProductImageDialog(
    properties: DialogProperties = DialogProperties(usePlatformDefaultWidth = false),
    onDismissRequest: () -> Unit
) {
    var scale by remember { mutableFloatStateOf(1f) }
    var offset by remember { mutableStateOf(Offset.Zero) }
    val coroutineScope = rememberCoroutineScope()

    var userScrollEnabled by remember { mutableStateOf(true) }

    val pagerState = rememberPagerState { 2 }

    Dialog(
        properties = properties,
        onDismissRequest = onDismissRequest
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Green),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.End
        ) {
            IconButton(onClick = onDismissRequest) {
                Icon(
                    imageVector = Icons.Default.Close,
                    tint = Color.White,
                    contentDescription = null
                )
            }

            Spacer(modifier = Modifier.height(8.dp))

            Column(
                modifier = Modifier
                    .background(color = Color.White)
                    .fillMaxWidth()
                    .fillMaxHeight(0.4f),
            ) {

//                items(2) { page ->
                    Image(
                        painter = painterResource(id = R.drawable.image_1),
                        contentDescription = null,
                        modifier = Modifier
                            .fillMaxSize()
                            .pointerInput(Unit) {
                                coroutineScope
                                    .launch {
                                        awaitPointerEventScope {
                                            while (true) {
                                                val event = awaitPointerEvent()
                                                when (event.changes.size) {
                                                    2 -> {
                                                        userScrollEnabled = false
                                                        val change1 = event.changes[0]
                                                        val change2 = event.changes[1]

                                                        val distanceCurrent = calculateDistance(
                                                            change1.position,
                                                            change2.position
                                                        )
                                                        val distancePrevious = calculateDistance(
                                                            change1.previousPosition,
                                                            change2.previousPosition
                                                        )
                                                        scale *= distanceCurrent / distancePrevious
                                                        offset += change1.positionChange()
                                                        Log.i(
                                                            "TAGTTTTTT",
                                                            "distanceCurrent: $distanceCurrent\ndistancePrevious: $distancePrevious\nscale: $scale\noffset: $offset"
                                                        )
                                                    }

                                                    else -> {
                                                        userScrollEnabled = true
                                                        scale = 1f
                                                        offset = Offset.Zero
                                                    }
                                                }
                                            }
                                        }
                                    }
                            }
                            .graphicsLayer(
                                scaleX = scale,
                                scaleY = scale,
                                translationX = offset.x,
                                translationY = offset.y
                            ),
                        contentScale = ContentScale.Inside
                    )
//                }

            }
        }
    }
}

private fun calculateDistance(point1: Offset, point2: Offset): Float {
    val dx = point1.x - point2.x
    val dy = point1.y - point2.y
    return sqrt(dx * dx + dy * dy)
}

Zommed in image Column Implemenation 这是使用 HorizontalPager 的代码:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ProductImageDialog(
    properties: DialogProperties = DialogProperties(usePlatformDefaultWidth = false),
    onDismissRequest: () -> Unit
) {
    var scale by remember { mutableFloatStateOf(1f) }
    var offset by remember { mutableStateOf(Offset.Zero) }
    val coroutineScope = rememberCoroutineScope()

    var userScrollEnabled by remember { mutableStateOf(true) }

    val pagerState = rememberPagerState { 2 }

    Dialog(
        properties = properties,
        onDismissRequest = onDismissRequest
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Green),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.End
        ) {
            IconButton(onClick = onDismissRequest) {
                Icon(
                    imageVector = Icons.Default.Close,
                    tint = Color.White,
                    contentDescription = null
                )
            }

            Spacer(modifier = Modifier.height(8.dp))

            HorizontalPager(
                modifier = Modifier
                    .background(color = Color.White)
                    .fillMaxWidth()
                    .fillMaxHeight(0.4f),
                state = pagerState,
                userScrollEnabled = userScrollEnabled,
            ) { page ->

                Image(
                    painter = if (page == 0) painterResource(id = R.drawable.image_1) else painterResource(id = R.drawable.image_2),
                    contentDescription = null,
                    modifier = Modifier
                        .fillMaxSize()
                        .pointerInput(Unit) {
                            coroutineScope
                                .launch {
                                    awaitPointerEventScope {
                                        while (true) {
                                            val event = awaitPointerEvent()
                                            when (event.changes.size) {
                                                2 -> {
                                                    userScrollEnabled = false
                                                    val change1 = event.changes[0]
                                                    val change2 = event.changes[1]

                                                    val distanceCurrent = calculateDistance(
                                                        change1.position,
                                                        change2.position
                                                    )
                                                    val distancePrevious = calculateDistance(
                                                        change1.previousPosition,
                                                        change2.previousPosition
                                                    )
                                                    scale *= distanceCurrent / distancePrevious
                                                    offset += change1.positionChange()
                                                    Log.i(
                                                        "TAGTTTTTT",
                                                        "distanceCurrent: $distanceCurrent\ndistancePrevious: $distancePrevious\nscale: $scale\noffset: $offset"
                                                    )
                                                }

                                                else -> {
                                                    userScrollEnabled = true
                                                    scale = 1f
                                                    offset = Offset.Zero
                                                }
                                            }
                                        }
                                    }
                                }
                        }
                        .graphicsLayer(
                            scaleX = scale,
                            scaleY = scale,
                            translationX = offset.x,
                            translationY = offset.y
                        ),
                    contentScale = ContentScale.Inside
                )
            }
        }
    }
}

Zoomed in image HorizontalPager implementation

android kotlin android-jetpack-compose zooming horizontal-pager
1个回答
0
投票

我通过向

HorizontalPager
而不是
Image
添加缩放修改器找到了解决方案。

代码:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ProductImageDialog(
    properties: DialogProperties = DialogProperties(usePlatformDefaultWidth = false),
    onDismissRequest: () -> Unit
) {
    var scale by remember { mutableFloatStateOf(1f) }
    var offset by remember { mutableStateOf(Offset.Zero) }
    val coroutineScope = rememberCoroutineScope()

    var userScrollEnabled by remember { mutableStateOf(true) }

    val pagerState = rememberPagerState { 2 }

    Dialog(
        properties = properties,
        onDismissRequest = onDismissRequest
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Green),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.End
        ) {
            IconButton(onClick = onDismissRequest) {
                Icon(
                    imageVector = Icons.Default.Close,
                    tint = Color.White,
                    contentDescription = null
                )
            }

            Spacer(modifier = Modifier.height(8.dp))

            HorizontalPager(
                modifier = Modifier
                    .background(color = Color.White)
                    .fillMaxWidth()
                    .fillMaxHeight(0.4f)
                    .pointerInput(Unit) {
                        coroutineScope
                            .launch {
                                awaitPointerEventScope {
                                    while (true) {
                                        val event = awaitPointerEvent()
                                        when (event.changes.size) {
                                            2 -> {
                                                userScrollEnabled = false
                                                val change1 = event.changes[0]
                                                val change2 = event.changes[1]

                                                val distanceCurrent = calculateDistance(
                                                    change1.position,
                                                    change2.position
                                                )
                                                val distancePrevious = calculateDistance(
                                                    change1.previousPosition,
                                                    change2.previousPosition
                                                )
                                                scale *= distanceCurrent / distancePrevious
                                                offset += change1.positionChange()
                                                Log.i(
                                                    "TAGTTTTTT",
                                                    "distanceCurrent: $distanceCurrent\ndistancePrevious: $distancePrevious\nscale: $scale\noffset: $offset"
                                                )
                                            }

                                            else -> {
                                                userScrollEnabled = true
                                                scale = 1f
                                                offset = Offset.Zero
                                            }
                                        }
                                    }
                                }
                            }
                    }
                    .graphicsLayer(
                        scaleX = scale,
                        scaleY = scale,
                        translationX = offset.x,
                        translationY = offset.y
                    ),
                state = pagerState,
                userScrollEnabled = userScrollEnabled,
            ) { page ->

                Image(
                    painter = if (page == 0) painterResource(id = R.drawable.image_1) else painterResource(
                        id = R.drawable.image_2
                    ),
                    contentDescription = null,
                    modifier = Modifier
                        .fillMaxSize(),
                    contentScale = ContentScale.Inside
                )
            }
        }
    }
}

private fun calculateDistance(point1: Offset, point2: Offset): Float {
    val dx = point1.x - point2.x
    val dy = point1.y - point2.y
    return sqrt(dx * dx + dy * dy)
}
© www.soinside.com 2019 - 2024. All rights reserved.