You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

73 lines
2.2 KiB

package example.imageviewer.model
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
class ScalableState(val imageSize: IntSize) {
var boxSize by mutableStateOf(IntSize(1, 1))
var offset by mutableStateOf(IntOffset.Zero)
var scale by mutableStateOf(1f)
}
val ScalableState.visiblePart
get() : IntRect {
val boxRatio = boxSize.width.toFloat() / boxSize.height
val imageRatio = imageSize.width.toFloat() / imageSize.height.toFloat()
val size: IntSize =
if (boxRatio > imageRatio) {
val height = imageSize.height / scale
val targetWidth = height * boxRatio
IntSize(minOf(imageSize.width, targetWidth.toInt()), height.toInt())
} else {
val width = imageSize.width / scale
val targetHeight = width / boxRatio
IntSize(width.toInt(), minOf(imageSize.height, targetHeight.toInt()))
}
return IntRect(offset = offset, size = size)
}
fun ScalableState.changeBoxSize(size: IntSize) {
boxSize = size
updateOffsetLimits()
}
fun ScalableState.setScale(scale: Float) {
this.scale = scale
updateOffsetLimits()
}
fun ScalableState.addScale(multiplier: Float) {
scale = (scale * multiplier).coerceIn(0.2f..5f)
updateOffsetLimits()
}
fun ScalableState.addDragAmount(diff: Offset) {
offset -= IntOffset((diff.x + 1).toInt(), (diff.y + 1).toInt())
updateOffsetLimits()
}
private fun ScalableState.updateOffsetLimits() {
if (offset.x + visiblePart.width > imageSize.width) {
changeOffset(x = imageSize.width - visiblePart.width)
}
if (offset.y + visiblePart.height > imageSize.height) {
changeOffset(y = imageSize.height - visiblePart.height)
}
if (offset.x < 0) {
changeOffset(x = 0)
}
if (offset.y < 0) {
changeOffset(y = 0)
}
}
private fun ScalableState.changeOffset(x: Int = offset.x, y: Int = offset.y) {
offset = IntOffset(x, y)
}