最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - Update offset in Magnification Gesture - Stack Overflow

programmeradmin0浏览0评论

Hi everyone I'm working on a black rectangle that contains a yellow rectangle inside it.. I implemented the DragGesture and the MagnificationGesture to interact with the yellow rectangle. The drag gesture works perfectly by keeping the movement of the yellow rectangle always within the limits of the black rectangle that contains it.

My problem is when I use the MagnificationGesture because when I zoom in on the yellow rectangle I can no longer move it, it's as if the drag gesture is not taken into consideration..

I need the yellow rectangle to be able to be moved as desired even after zooming but always remaining within the limits of the black rectangle set within the DragGesture. Thanks for all

struct ContentView: View {
    @State private var offset: CGSize = .zero
    @State private var lastOffset: CGSize = .zero
    @State private var scale: CGFloat = 1.0
    @State private var lastScale: CGFloat = 1.0
    
    let imageSize: CGSize = .init(width: 150, height: 150)
    let containerSize: CGSize = .init(width: 300, height: 300)
    
    var body: some View {
        Rectangle()
            .stroke(.white, lineWidth: 2)
            .frame(containerSize)
            .background {
                GeometryReader {
                    let size = $0.size
                    Rectangle()
                        .fill(.yellow)
                        .frame(width: imageSize.width * scale, height: imageSize.height * scale)
                        .scaleEffect(scale)
                        .offset(offset)
                        .gesture(
                            MagnificationGesture()
                                .onChanged { value in
                                    let newScale = lastScale * value
                                    scale = min(max(newScale, 1), 3)
                                }
                                .onEnded { _ in
                                    lastScale = scale
                                })
                        .simultaneousGesture(
                            DragGesture()
                                .onChanged { value in
                                    let translation = value.translation
                                    let scaledImageSize: CGSize = .init(width: imageSize.width * scale, height: imageSize.height * scale)
                                    
                                    let xLimit = max(min(lastOffset.width + translation.width, size.width - scaledImageSize.width), 0)
                                    
                                    let yLimit = max(min(lastOffset.height + translation.height, size.height - scaledImageSize.height), 0)
                                    
                                    offset = CGSize(width: xLimit, height: yLimit)
                                }
                                .onEnded { value in
                                    lastOffset = offset
                                }
                        )
                }
            }
    }
}

Hi everyone I'm working on a black rectangle that contains a yellow rectangle inside it.. I implemented the DragGesture and the MagnificationGesture to interact with the yellow rectangle. The drag gesture works perfectly by keeping the movement of the yellow rectangle always within the limits of the black rectangle that contains it.

My problem is when I use the MagnificationGesture because when I zoom in on the yellow rectangle I can no longer move it, it's as if the drag gesture is not taken into consideration..

I need the yellow rectangle to be able to be moved as desired even after zooming but always remaining within the limits of the black rectangle set within the DragGesture. Thanks for all

struct ContentView: View {
    @State private var offset: CGSize = .zero
    @State private var lastOffset: CGSize = .zero
    @State private var scale: CGFloat = 1.0
    @State private var lastScale: CGFloat = 1.0
    
    let imageSize: CGSize = .init(width: 150, height: 150)
    let containerSize: CGSize = .init(width: 300, height: 300)
    
    var body: some View {
        Rectangle()
            .stroke(.white, lineWidth: 2)
            .frame(containerSize)
            .background {
                GeometryReader {
                    let size = $0.size
                    Rectangle()
                        .fill(.yellow)
                        .frame(width: imageSize.width * scale, height: imageSize.height * scale)
                        .scaleEffect(scale)
                        .offset(offset)
                        .gesture(
                            MagnificationGesture()
                                .onChanged { value in
                                    let newScale = lastScale * value
                                    scale = min(max(newScale, 1), 3)
                                }
                                .onEnded { _ in
                                    lastScale = scale
                                })
                        .simultaneousGesture(
                            DragGesture()
                                .onChanged { value in
                                    let translation = value.translation
                                    let scaledImageSize: CGSize = .init(width: imageSize.width * scale, height: imageSize.height * scale)
                                    
                                    let xLimit = max(min(lastOffset.width + translation.width, size.width - scaledImageSize.width), 0)
                                    
                                    let yLimit = max(min(lastOffset.height + translation.height, size.height - scaledImageSize.height), 0)
                                    
                                    offset = CGSize(width: xLimit, height: yLimit)
                                }
                                .onEnded { value in
                                    lastOffset = offset
                                }
                        )
                }
            }
    }
}
Share Improve this question edited Nov 20, 2024 at 11:40 Benzy Neez 22.5k3 gold badges15 silver badges43 bronze badges asked Nov 20, 2024 at 10:55 kAiNkAiN 2,7932 gold badges30 silver badges64 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

It looks like you are applying the scaling twice, because you are also scaling the sizes being applied with the .frame modifier.

Try commenting out the scaleEffect modifier:

Rectangle()
    .fill(.yellow)
    .frame(width: imageSize.width * scale, height: imageSize.height * scale)
    // .scaleEffect(scale)
    // + other modifiers

This resolves the bounds issue when dragged. However, you were asking in a comment, how to let the yellow rectangle scale in all directions while still staying within bounds? This will require updating the offset inside the magnification gesture. Something like:

MagnificationGesture()
    .onChanged { value in
        let maxScale = min(size.width / imageSize.width, size.height / imageSize.height)
        let newScale = min(max(lastScale * value, 1), maxScale)

        // Adjust the offset to simulate a scaling anchor of .center
        // and to keep the scaled rectangle within bounds
        let prevAdjustmentX = imageSize.width * (scale - 1) / 2
        let newAdjustmentX = imageSize.width * (newScale - 1) / 2
        let dx = prevAdjustmentX - newAdjustmentX
        let prevAdjustmentY = imageSize.height * (scale - 1) / 2
        let newAdjustmentY = imageSize.height * (newScale - 1) / 2
        let dy = prevAdjustmentY - newAdjustmentY
        let x = min(max(0, offset.width + dx), size.width - (imageSize.width * newScale))
        let y = min(max(0, offset.height + dy), size.height - (imageSize.height * newScale))
        offset = CGSize(width: x, height: y)
        lastOffset = offset
        scale = newScale
    }
    .onEnded { _ in
        lastScale = scale
    }

发布评论

评论列表(0)

  1. 暂无评论