如何防止图像平移超出图像框(或屏幕)

时间:2019-11-23 20:59:12

标签: ios swift swiftui

如果您玩过Apple的Room Tutorial(链接:../WWDC2019/204/),则按照以下代码,我添加了一个小的触摸缩放手势(由于@Alladinian和brar07)。

但是,触摸和平移图像时,图像会移出屏幕,并且不会返回其原始位置。 只需少量修改,您就可以将此代码复制并粘贴到Apple的项目中

要求 1):图像应停留在图像框的范围内,即,缩放时,图像的边缘不应超出图像边缘。定义的框架(如果未定义框架,则为屏幕)。 2):图像应返回其原始位置。

最终结果类似于某些网站上产品图片的鼠标悬停方式

import SwiftUI


struct RoomDetail: View {

    let room : Room

    @State var scale: CGFloat = 1.0
    @State var isTouchingScreen = false
    @State var isZoomedIn = false
    @State var pointTouchedOnScreen: CGPoint = CGPoint.zero
    @State var panSize: CGSize = CGSize.zero
    @State var fingerState: String = "Finger is not touching the image"

    var body: some View {
        ZStack {

            // Show the room selected by the user, implement zooming capabilities
            GeometryReader { reader in

                Image("\(self.room.name)" + "_Thumb")
                    .resizable()
                    .offset(x: self.panSize.width, y: self.panSize.height)
                    .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)

                        .onChanged {  (value) in

                            self.fingerState = "Finger is touching the image" // for debug purpose only

                            self.isZoomedIn = true

                            self.isTouchingScreen = true

                            self.pointTouchedOnScreen = value.startLocation

                            self.scale = 1.1


                            let offsetWidth = (reader.frame(in: .global).maxX * self.scale - reader.frame(in: .global).maxX) / 2

                            let newDraggedWidth = self.panSize.width * self.scale

                            if (newDraggedWidth > offsetWidth) {
                                self.panSize = CGSize(width: (value.translation.width + self.panSize.width), height: (value.translation.height + self.panSize.height))
                            } else if (newDraggedWidth <  -offsetWidth) {
                                self.panSize = CGSize(width: (value.translation.width + self.panSize.width), height: (value.translation.height + self.panSize.height))
                            } else {
                                self.panSize = CGSize(width: (value.translation.width + self.panSize.width), height: (value.translation.height + self.panSize.height))
                            }
                    }

                    .onEnded { _ in

                        self.fingerState = "Finger is not touching the image" // for debug purpose only

                        self.isZoomedIn = false

                        self.isTouchingScreen = false


                    })
                        .aspectRatio(contentMode: self.isZoomedIn ? .fill : .fit)
                        .scaleEffect(self.isTouchingScreen ? self.scale : 1, anchor: UnitPoint(x: self.pointTouchedOnScreen.x / reader.frame(in: .global).maxX, y: self.pointTouchedOnScreen.y / reader.frame(in: .global).maxY))
                        .animation(.easeInOut(duration: 1))
                        .frame(maxWidth: UIScreen.main.bounds.size.width - 50, maxHeight: UIScreen.main.bounds.size.height - 200, alignment: .center)
                        .clipped()
                        .offset(x: 0, y: -50)
        }
    }
}

struct RoomDetail_Previews: PreviewProvider {
    static var previews: some View {
        RoomDetail(room: testData[0])
    }
}

1 个答案:

答案 0 :(得分:1)

我不知道这是否能准确回答您的问题,但我想做个注释:

  • 修饰符的顺序
  • 我试图做一个变焦效果, 它一直超过图像的帧
  • 但是,当我在缩放效果之后设置FRAME时,它保持在范围之内

这不起作用,图像将不会“裁剪”为图像框架的大小:

Image(uiImage: self.userData.image!)
.resizable()
.offset(x: self.currentPosition.width, y: self.currentPosition.height)
.aspectRatio(contentMode: .fill)
.frame(maxWidth:metrics.size.width * 0.60, maxHeight: metrics.size.height * 0.60, alignment: .top)
.scaleEffect(self.scale)
.clipped()
.foregroundColor(.gray)

此DID起作用:

Image(uiImage: self.userData.image!)
.resizable()
.scaleEffect(self.scale)
.offset(x: self.currentPosition.width, y: self.currentPosition.height)
.aspectRatio(contentMode: .fill)
.frame(maxWidth:metrics.size.width * 0.60, maxHeight: metrics.size.height * 0.60, alignment: .top)  
.clipped()
.foregroundColor(.gray)

唯一的区别是在帧之前应用了scaleEffect。 (在这种情况下,我有拖动手势和缩放手势)。

花了很多时间试图解决这个问题,但不确定它是否能解决您的问题,但可能对某人有用。