Зум и пролистывание
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,11 @@ package core.presentation.components
|
|||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.gestures.calculatePan
|
||||||
|
import androidx.compose.foundation.gestures.calculateZoom
|
||||||
import androidx.compose.foundation.gestures.detectTransformGestures
|
import androidx.compose.foundation.gestures.detectTransformGestures
|
||||||
|
import androidx.compose.foundation.gestures.awaitEachGesture
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
import androidx.compose.foundation.gestures.rememberTransformableState
|
import androidx.compose.foundation.gestures.rememberTransformableState
|
||||||
import androidx.compose.foundation.gestures.transformable
|
import androidx.compose.foundation.gestures.transformable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@@ -22,6 +26,7 @@ import androidx.compose.ui.graphics.graphicsLayer
|
|||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
@@ -43,6 +48,7 @@ fun AppMediaLightbox(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val pagerState = rememberPagerState(initialPage = initialIndex, pageCount = { mediaList.size })
|
val pagerState = rememberPagerState(initialPage = initialIndex, pageCount = { mediaList.size })
|
||||||
|
var canScroll by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
Dialog(
|
Dialog(
|
||||||
onDismissRequest = onClose,
|
onDismissRequest = onClose,
|
||||||
@@ -60,7 +66,8 @@ fun AppMediaLightbox(
|
|||||||
state = pagerState,
|
state = pagerState,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
pageSpacing = 16.dp,
|
pageSpacing = 16.dp,
|
||||||
beyondBoundsPageCount = 1
|
beyondBoundsPageCount = 1,
|
||||||
|
userScrollEnabled = canScroll
|
||||||
) { page ->
|
) { page ->
|
||||||
val media = mediaList[page]
|
val media = mediaList[page]
|
||||||
|
|
||||||
@@ -80,6 +87,60 @@ fun AppMediaLightbox(
|
|||||||
var scale by remember { mutableFloatStateOf(1f) }
|
var scale by remember { mutableFloatStateOf(1f) }
|
||||||
var offset by remember { mutableStateOf(androidx.compose.ui.geometry.Offset.Zero) }
|
var offset by remember { mutableStateOf(androidx.compose.ui.geometry.Offset.Zero) }
|
||||||
|
|
||||||
|
// Reset zoom when page changes
|
||||||
|
LaunchedEffect(pagerState.currentPage) {
|
||||||
|
scale = 1f
|
||||||
|
offset = androidx.compose.ui.geometry.Offset.Zero
|
||||||
|
canScroll = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
detectTapGestures(
|
||||||
|
onDoubleTap = {
|
||||||
|
if (scale > 1f) {
|
||||||
|
scale = 1f
|
||||||
|
offset = Offset.Zero
|
||||||
|
canScroll = true
|
||||||
|
} else {
|
||||||
|
scale = 3f
|
||||||
|
canScroll = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.pointerInput(Unit) {
|
||||||
|
awaitEachGesture {
|
||||||
|
do {
|
||||||
|
val event = awaitPointerEvent()
|
||||||
|
val zoomActive = scale > 1f || event.changes.size > 1
|
||||||
|
|
||||||
|
if (zoomActive) {
|
||||||
|
// Если мы в режиме зума - поглощаем события
|
||||||
|
event.changes.forEach { it.consume() }
|
||||||
|
|
||||||
|
// Сами вычисляем трансформацию
|
||||||
|
val zoomChange = event.calculateZoom()
|
||||||
|
val panChange = event.calculatePan()
|
||||||
|
|
||||||
|
scale = (scale * zoomChange).coerceIn(1f, 5f)
|
||||||
|
canScroll = scale <= 1f
|
||||||
|
|
||||||
|
if (scale > 1f) {
|
||||||
|
offset += panChange
|
||||||
|
} else {
|
||||||
|
offset = Offset.Zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Если zoomActive == false, мы НЕ вызываем consume(),
|
||||||
|
// и событие уходит наверх в HorizontalPager
|
||||||
|
} while (event.changes.any { it.pressed })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = media.url,
|
model = media.url,
|
||||||
imageLoader = core.utils.CoilUtils.getGifImageLoader(LocalContext.current),
|
imageLoader = core.utils.CoilUtils.getGifImageLoader(LocalContext.current),
|
||||||
@@ -94,7 +155,9 @@ fun AppMediaLightbox(
|
|||||||
),
|
),
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
// Document / File placeholder in Lightbox
|
// Document / File placeholder in Lightbox
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize().padding(32.dp),
|
modifier = Modifier.fillMaxSize().padding(32.dp),
|
||||||
|
|||||||
Reference in New Issue
Block a user