如何设置此代码以从图像的任何位置放大?
How can I set this code up to zoom in from anywhere on the image?
我正在编写一些代码,允许用户在应用程序的图像上使用各种手势。我想要的是了解如何允许用户捏合或双击图像中的特定位置。现在,他们只能从中心缩放,否则缩放会得到意想不到的结果。我选择这条路径是因为它同时使用了 SwiftUI 和拖动关闭功能。谢谢!
import SwiftUI
public struct SampleZoom {
@ObservedObject
private var viewModel: ViewModel
@State private var currentZoom: CGFloat = 0
@State private var endingZoom: CGFloat = 1
@State private var isZoomed = false
@State private var pointTapped: CGPoint = .zero
@GestureState var swipeOffset: CGSize = .zero
public init(viewModel: ViewModel) {
self.viewModel = viewModel
}
}
extension SampleZoom: View {
public var body: some View {
if viewModel.isVisible {
ZStack {
Color.black
.opacity(viewModel.bgOpacity)
.edgesIgnoringSafeArea(.all)
image(imageData: viewModel.image)
}
.onAppear {
endingZoom = 1
isZoomed = false
}
.overlay(
/// Close Button
Button(action: {
viewModel.isVisible.toggle()
}, label: {
Image(systemName: "xmark")
.foregroundColor(.white)
.padding()
.background(Color.white.opacity(0.33))
.clipShape(Circle())
})
.padding(Spacing.standard), alignment: .topLeading
)
} else {
Spacer()
}
}
}
private extension SampleZoom {
/// Creates card Image
func image(imageData: Data) -> some View {
GeometryReader { reader in
Image("Your Image Here!")
.resizable()
.aspectRatio(contentMode: .fit)
.offset(y: viewModel.imageOffset.height)
.animation(.default)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.scaleEffect(endingZoom + currentZoom > 1 ? endingZoom + currentZoom : 1, anchor: UnitPoint(
x: pointTapped.x / reader.frame(in: .global).maxX,
y: pointTapped.y / reader.frame(in: .global).maxY
))
/// Double tap to zoom
.gesture(
TapGesture(count: 2).onEnded {
withAnimation {
isZoomed.toggle()
endingZoom = endingZoom > 1 ? 1 : 2
}
}
.simultaneously(
with: DragGesture(minimumDistance: 0, coordinateSpace: .global).onChanged { value in
if !isZoomed {
pointTapped = value.startLocation
}
}
/// Swipe & close interactions
.updating($swipeOffset) { value, outValue, _ in
outValue = value.translation
viewModel.onChange(imagePosition: swipeOffset)
}
.onEnded(viewModel.onEnd(swipeDistance:))
)
)
/// Pinch & zoom interactions
.gesture(
MagnificationGesture()
.onChanged { amount in
currentZoom = amount - 1
}
.onEnded { _ in
endingZoom += currentZoom
currentZoom = 0
isZoomed = endingZoom + currentZoom > 1 ? true : false
}
)
}
}
}
public extension SampleZoom {
final class ViewModel: ObservableObject {
let image: Data
@Published
var isVisible: Bool
@Published
var imageOffset: CGSize = .zero
@Published
var bgOpacity: Double = 1
func onChange(imagePosition: CGSize) {
imageOffset = imagePosition
let halfScreenHeight = UIScreen.main.bounds.height / 2
let progress = imagePosition.height / halfScreenHeight
withAnimation(.default) {
bgOpacity = Double(1 - (progress < 0 ? -progress : progress))
}
}
func onEnd(swipeDistance: DragGesture.Value) {
withAnimation(.easeOut) {
var translation = swipeDistance.translation.height
if translation < Spacing.none {
translation = -translation
}
if translation < Spacing.doubleExtraLarge * 3 {
imageOffset.height = Spacing.none
bgOpacity = 1
} else {
isVisible.toggle()
imageOffset.height = Spacing.none
bgOpacity = 1
}
}
}
init(image: Data, isVisible: Bool) {
self.image = image
self.isVisible = isVisible
}
}
}
在 UIScrollView 的帮助下,您可以非常轻松地缩放到您的 imageView。添加 UIScrollView 并在内部添加 imageView。然后实现 UIScrollViewDelegate 和函数 viewForZooming
override func viewDidLoad() {
super.viewDidLoad()
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 10.0
scrollView.delegate = self
}
extension YourVC: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return image
}
}
我正在编写一些代码,允许用户在应用程序的图像上使用各种手势。我想要的是了解如何允许用户捏合或双击图像中的特定位置。现在,他们只能从中心缩放,否则缩放会得到意想不到的结果。我选择这条路径是因为它同时使用了 SwiftUI 和拖动关闭功能。谢谢!
import SwiftUI
public struct SampleZoom {
@ObservedObject
private var viewModel: ViewModel
@State private var currentZoom: CGFloat = 0
@State private var endingZoom: CGFloat = 1
@State private var isZoomed = false
@State private var pointTapped: CGPoint = .zero
@GestureState var swipeOffset: CGSize = .zero
public init(viewModel: ViewModel) {
self.viewModel = viewModel
}
}
extension SampleZoom: View {
public var body: some View {
if viewModel.isVisible {
ZStack {
Color.black
.opacity(viewModel.bgOpacity)
.edgesIgnoringSafeArea(.all)
image(imageData: viewModel.image)
}
.onAppear {
endingZoom = 1
isZoomed = false
}
.overlay(
/// Close Button
Button(action: {
viewModel.isVisible.toggle()
}, label: {
Image(systemName: "xmark")
.foregroundColor(.white)
.padding()
.background(Color.white.opacity(0.33))
.clipShape(Circle())
})
.padding(Spacing.standard), alignment: .topLeading
)
} else {
Spacer()
}
}
}
private extension SampleZoom {
/// Creates card Image
func image(imageData: Data) -> some View {
GeometryReader { reader in
Image("Your Image Here!")
.resizable()
.aspectRatio(contentMode: .fit)
.offset(y: viewModel.imageOffset.height)
.animation(.default)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.scaleEffect(endingZoom + currentZoom > 1 ? endingZoom + currentZoom : 1, anchor: UnitPoint(
x: pointTapped.x / reader.frame(in: .global).maxX,
y: pointTapped.y / reader.frame(in: .global).maxY
))
/// Double tap to zoom
.gesture(
TapGesture(count: 2).onEnded {
withAnimation {
isZoomed.toggle()
endingZoom = endingZoom > 1 ? 1 : 2
}
}
.simultaneously(
with: DragGesture(minimumDistance: 0, coordinateSpace: .global).onChanged { value in
if !isZoomed {
pointTapped = value.startLocation
}
}
/// Swipe & close interactions
.updating($swipeOffset) { value, outValue, _ in
outValue = value.translation
viewModel.onChange(imagePosition: swipeOffset)
}
.onEnded(viewModel.onEnd(swipeDistance:))
)
)
/// Pinch & zoom interactions
.gesture(
MagnificationGesture()
.onChanged { amount in
currentZoom = amount - 1
}
.onEnded { _ in
endingZoom += currentZoom
currentZoom = 0
isZoomed = endingZoom + currentZoom > 1 ? true : false
}
)
}
}
}
public extension SampleZoom {
final class ViewModel: ObservableObject {
let image: Data
@Published
var isVisible: Bool
@Published
var imageOffset: CGSize = .zero
@Published
var bgOpacity: Double = 1
func onChange(imagePosition: CGSize) {
imageOffset = imagePosition
let halfScreenHeight = UIScreen.main.bounds.height / 2
let progress = imagePosition.height / halfScreenHeight
withAnimation(.default) {
bgOpacity = Double(1 - (progress < 0 ? -progress : progress))
}
}
func onEnd(swipeDistance: DragGesture.Value) {
withAnimation(.easeOut) {
var translation = swipeDistance.translation.height
if translation < Spacing.none {
translation = -translation
}
if translation < Spacing.doubleExtraLarge * 3 {
imageOffset.height = Spacing.none
bgOpacity = 1
} else {
isVisible.toggle()
imageOffset.height = Spacing.none
bgOpacity = 1
}
}
}
init(image: Data, isVisible: Bool) {
self.image = image
self.isVisible = isVisible
}
}
}
在 UIScrollView 的帮助下,您可以非常轻松地缩放到您的 imageView。添加 UIScrollView 并在内部添加 imageView。然后实现 UIScrollViewDelegate 和函数 viewForZooming
override func viewDidLoad() {
super.viewDidLoad()
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 10.0
scrollView.delegate = self
}
extension YourVC: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return image
}
}