如何在 SwiftUI 中捏合和滚动图像?
How to pinch and scroll an image in SwiftUI?
我想在我的应用程序中添加一个图像查看器,但我无法实现它。我想显示一个图像并允许用户在图像中捏合和滚动以详细检查它。根据我从多个 Internet 帖子中收集到的内容,我有一些工作,但不完全是。这是我的代码:
import SwiftUI
struct ContentView: View {
@State var currentScale: CGFloat = 1.0
@State var previousScale: CGFloat = 1.0
@State var currentOffset = CGSize.zero
@State var previousOffset = CGSize.zero
var body: some View {
ZStack {
Image("bulldog2")
.resizable()
.edgesIgnoringSafeArea(.all)
.aspectRatio(contentMode: .fit)
.offset(x: self.currentOffset.width, y: self.currentOffset.height)
.scaleEffect(self.currentScale)
.gesture(DragGesture()
.onChanged { value in
let deltaX = value.translation.width - self.previousOffset.width
let deltaY = value.translation.height - self.previousOffset.height
self.previousOffset.width = value.translation.width
self.previousOffset.height = value.translation.height
self.currentOffset.width = self.currentOffset.width + deltaX / self.currentScale
self.currentOffset.height = self.currentOffset.height + deltaY / self.currentScale }
.onEnded { value in self.previousOffset = CGSize.zero })
.gesture(MagnificationGesture()
.onChanged { value in
let delta = value / self.previousScale
self.previousScale = value
self.currentScale = self.currentScale * delta
}
.onEnded { value in self.previousScale = 1.0 })
VStack {
Spacer()
HStack {
Text("Menu 1").padding().background(Color.white).cornerRadius(30).padding()
Spacer()
Text("Menu 2").padding().background(Color.white).cornerRadius(30).padding()
}
}
}
}
}
初始视图如下所示:
我遇到的第一个问题是我可以将图像移动得太远,以至于我可以看到图像外部。如果图像移动得太远,这可能会导致图像在应用程序中不再可见。
第二个问题不是很大,我可以缩小图像但与视图相比它变得太小了。我想限制它,使 "fit" 成为它的最小尺寸。有没有比约束 self.currentScale
和 self.previousScale
更好的方法?
第三个问题是,如果我更改图像以填充 space,底部菜单会变得比 phone 的屏幕大。
我不是 iOS 开发人员,可能有更好的方法来实现此功能。谢谢你的帮助。
我可以回答 3 个问题中的 2 个。第三个不能重复了
- 您可以使用
GeometryReader
并使用它的 frame
和 size
进行一些限制(我将在下面的示例中展示);
- 也许最简单和更好的方法就是使用
max
函数,例如 .scaleEffect(max(self.currentScale, 1.0))
.
这里是改变的例子:
struct BulldogImageViewerView: View {
@State var currentScale: CGFloat = 1.0
@State var previousScale: CGFloat = 1.0
@State var currentOffset = CGSize.zero
@State var previousOffset = CGSize.zero
var body: some View {
ZStack {
GeometryReader { geometry in // here you'll have size and frame
Image("bulldog")
.resizable()
.edgesIgnoringSafeArea(.all)
.aspectRatio(contentMode: .fit)
.offset(x: self.currentOffset.width, y: self.currentOffset.height)
.scaleEffect(max(self.currentScale, 1.0)) // the second question
.gesture(DragGesture()
.onChanged { value in
let deltaX = value.translation.width - self.previousOffset.width
let deltaY = value.translation.height - self.previousOffset.height
self.previousOffset.width = value.translation.width
self.previousOffset.height = value.translation.height
let newOffsetWidth = self.currentOffset.width + deltaX / self.currentScale
// question 1: how to add horizontal constraint (but you need to think about scale)
if newOffsetWidth <= geometry.size.width - 150.0 && newOffsetWidth > -150.0 {
self.currentOffset.width = self.currentOffset.width + deltaX / self.currentScale
}
self.currentOffset.height = self.currentOffset.height + deltaY / self.currentScale }
.onEnded { value in self.previousOffset = CGSize.zero })
.gesture(MagnificationGesture()
.onChanged { value in
let delta = value / self.previousScale
self.previousScale = value
self.currentScale = self.currentScale * delta
}
.onEnded { value in self.previousScale = 1.0 })
}
VStack {
Spacer()
HStack {
Text("Menu 1").padding().cornerRadius(30).background(Color.blue).padding()
Spacer()
Text("Menu 2").padding().cornerRadius(30).background(Color.blue).padding()
}
}
}
}
}
用这段代码我实现了:
用户不能水平方向将图片移离屏幕;
用户不能缩小图片;
我想在我的应用程序中添加一个图像查看器,但我无法实现它。我想显示一个图像并允许用户在图像中捏合和滚动以详细检查它。根据我从多个 Internet 帖子中收集到的内容,我有一些工作,但不完全是。这是我的代码:
import SwiftUI
struct ContentView: View {
@State var currentScale: CGFloat = 1.0
@State var previousScale: CGFloat = 1.0
@State var currentOffset = CGSize.zero
@State var previousOffset = CGSize.zero
var body: some View {
ZStack {
Image("bulldog2")
.resizable()
.edgesIgnoringSafeArea(.all)
.aspectRatio(contentMode: .fit)
.offset(x: self.currentOffset.width, y: self.currentOffset.height)
.scaleEffect(self.currentScale)
.gesture(DragGesture()
.onChanged { value in
let deltaX = value.translation.width - self.previousOffset.width
let deltaY = value.translation.height - self.previousOffset.height
self.previousOffset.width = value.translation.width
self.previousOffset.height = value.translation.height
self.currentOffset.width = self.currentOffset.width + deltaX / self.currentScale
self.currentOffset.height = self.currentOffset.height + deltaY / self.currentScale }
.onEnded { value in self.previousOffset = CGSize.zero })
.gesture(MagnificationGesture()
.onChanged { value in
let delta = value / self.previousScale
self.previousScale = value
self.currentScale = self.currentScale * delta
}
.onEnded { value in self.previousScale = 1.0 })
VStack {
Spacer()
HStack {
Text("Menu 1").padding().background(Color.white).cornerRadius(30).padding()
Spacer()
Text("Menu 2").padding().background(Color.white).cornerRadius(30).padding()
}
}
}
}
}
初始视图如下所示:
我遇到的第一个问题是我可以将图像移动得太远,以至于我可以看到图像外部。如果图像移动得太远,这可能会导致图像在应用程序中不再可见。
第二个问题不是很大,我可以缩小图像但与视图相比它变得太小了。我想限制它,使 "fit" 成为它的最小尺寸。有没有比约束 self.currentScale
和 self.previousScale
更好的方法?
第三个问题是,如果我更改图像以填充 space,底部菜单会变得比 phone 的屏幕大。
我不是 iOS 开发人员,可能有更好的方法来实现此功能。谢谢你的帮助。
我可以回答 3 个问题中的 2 个。第三个不能重复了
- 您可以使用
GeometryReader
并使用它的frame
和size
进行一些限制(我将在下面的示例中展示); - 也许最简单和更好的方法就是使用
max
函数,例如.scaleEffect(max(self.currentScale, 1.0))
.
这里是改变的例子:
struct BulldogImageViewerView: View {
@State var currentScale: CGFloat = 1.0
@State var previousScale: CGFloat = 1.0
@State var currentOffset = CGSize.zero
@State var previousOffset = CGSize.zero
var body: some View {
ZStack {
GeometryReader { geometry in // here you'll have size and frame
Image("bulldog")
.resizable()
.edgesIgnoringSafeArea(.all)
.aspectRatio(contentMode: .fit)
.offset(x: self.currentOffset.width, y: self.currentOffset.height)
.scaleEffect(max(self.currentScale, 1.0)) // the second question
.gesture(DragGesture()
.onChanged { value in
let deltaX = value.translation.width - self.previousOffset.width
let deltaY = value.translation.height - self.previousOffset.height
self.previousOffset.width = value.translation.width
self.previousOffset.height = value.translation.height
let newOffsetWidth = self.currentOffset.width + deltaX / self.currentScale
// question 1: how to add horizontal constraint (but you need to think about scale)
if newOffsetWidth <= geometry.size.width - 150.0 && newOffsetWidth > -150.0 {
self.currentOffset.width = self.currentOffset.width + deltaX / self.currentScale
}
self.currentOffset.height = self.currentOffset.height + deltaY / self.currentScale }
.onEnded { value in self.previousOffset = CGSize.zero })
.gesture(MagnificationGesture()
.onChanged { value in
let delta = value / self.previousScale
self.previousScale = value
self.currentScale = self.currentScale * delta
}
.onEnded { value in self.previousScale = 1.0 })
}
VStack {
Spacer()
HStack {
Text("Menu 1").padding().cornerRadius(30).background(Color.blue).padding()
Spacer()
Text("Menu 2").padding().cornerRadius(30).background(Color.blue).padding()
}
}
}
}
}
用这段代码我实现了:
用户不能水平方向将图片移离屏幕;
用户不能缩小图片;