I'm trying to implement the box with the fixed aspect ratio that helps user to frame the image before it gets cropped. They may zoom in/out and move the image but the container must stay filled.
I'm struggling with blocking an (arbitrary) image from being dragged to the left (or to the top) to the point when only part of it stays in container, i.e. if a user loads vertical image, the horizontal scroll should not work until they zoom in, but if it's a horizontal image then the vertical scroll should not work. However, when the image is zoomed in.
Here is the code that I'm trying to use (that doesn't work since the key dimensions are missing).
struct ZoomableImageView: View {
@Binding var image: Image?
@State private var scale: CGFloat = 1.0
@State private var lastScaleValue: CGFloat = 1.0
@State private var offset: CGSize = CGSize.zero
@State private var draggedSize: CGSize = CGSize.zero
var body: some View {
GeometryReader { reader in
image?
.resizable()
.scaledToFill()
.scaleEffect(self.scale)
.offset(x: self.offset.width, y: self.offset.height)
.gesture(
MagnificationGesture()
.onChanged { (scale) in
self.scale = max(scale.magnitude * self.lastScaleValue, 1.0)
}.onEnded { _ in
self.lastScaleValue = self.scale
})
.simultaneousGesture(
DragGesture(minimumDistance: 0, coordinateSpace: .global)
.onChanged({ value in
// It should be -(image.width - reader.size.width) so the scroll is blocked when there's no more content
self.offset.width = max(min(value.translation.width + draggedSize.width, 0), -reader.size.width)
self.offset.height = max(min(value.translation.height + draggedSize.height, 0), -reader.size.height)
})
.onEnded({ value in
draggedSize = self.offset
})
)
}
}
}
In this code, reader.size is a block that is actually visible on the screen and says nothing about the underlying image. Is it possible to access the actual size of image in runtime (or put it into a state var during the load)?