ios - 在 SwiftUI 中,如何使手势在容器 View 之外处于非事件状态?

标签 ios swiftui gesture clipping

我正在尝试使 View 仅在其剪辑容器 View 内可拖动和/或可缩放(否则它可能会遇到并与其他 View 的手势冲突),但到目前为止我没有尝试过阻止手势延伸到可见之外容器的边界。
这是 I 行为的简化演示不要想...
当红色 Rectangle 部分超出绿色 VStack 区域(剪裁)时,它会响应超出绿色区域的拖动手势:
Drag not limited by container

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    
    @State var position: CGPoint = CGPoint(x: 100, y: 150)
    @State var lastPosition: CGPoint = CGPoint(x: 100, y: 150)
    
    var body: some View {
        
        let drag = DragGesture()
        .onChanged {
            self.position = CGPoint(x: $0.translation.width + self.lastPosition.x, y: $0.translation.height + self.lastPosition.y)
        }
        .onEnded {_ in
            self.lastPosition = self.position
        }
        
        return VStack {
            Rectangle().foregroundColor(.red)
                .frame(width: 150, height: 150)
                .position(self.position)
                .gesture(drag)
                .clipped()
        }
        .background(Color.green)
        .frame(width: 200, height: 300)
        
    }
}

PlaygroundPage.current.setLiveView(ContentView())
您如何将此手势限制为仅在容器内工作(上例中的绿色区域)?
更新:
@Asperi 对上述问题的解决方案效果很好,但是当我在上面的容器旁边添加第二个可拖动容器时,我在第一个容器中得到一个“死区”,我无法在其中拖动(它似乎是第二个正方形的位置如果它没有被剪裁,将覆盖第一个)。问题只发生在原始/左侧,而不是新的。我认为这与它具有更高的优先级有关,因为它被排在第二位。
这是新问题的说明:
2 Containers create dragging dead zone
这是更新的代码:
struct ContentView: View {
    
    @State var position1: CGPoint = CGPoint(x: 100, y: 150)
    @State var lastPosition1: CGPoint = CGPoint(x: 100, y: 150)
    let dragArea1: CGRect = CGRect(x: 0, y: 0, width: 200, height: 300)
    
    @State var position2: CGPoint = CGPoint(x: 100, y: 150)
    @State var lastPosition2: CGPoint = CGPoint(x: 100, y: 150)
    let dragArea2: CGRect = CGRect(x: 0, y: 0, width: 200, height: 300)
    
    var body: some View {

        let drag1 = DragGesture(coordinateSpace: .named("dragArea1"))
        .onChanged {
            guard self.dragArea1.contains($0.startLocation) else { return }
            self.position1 = CGPoint(x: $0.translation.width + self.lastPosition1.x, y: $0.translation.height + self.lastPosition1.y)
        }
        .onEnded {_ in
            self.lastPosition1 = self.position1
        }
        
        let drag2 = DragGesture(coordinateSpace: .named("dragArea2"))
        .onChanged {
            guard self.dragArea2.contains($0.startLocation) else { return }
            self.position2 = CGPoint(x: $0.translation.width + self.lastPosition2.x, y: $0.translation.height + self.lastPosition2.y)
        }
        .onEnded {_ in
            self.lastPosition2 = self.position2
        }
        
        return HStack {
            VStack {
                Rectangle().foregroundColor(.red)
                    .frame(width: 150, height: 150)
                    .position(self.position1)
                    .gesture(drag1)
                    .clipped()
            }
            .background(Color.green)
            .frame(width: dragArea1.width, height: dragArea1.height)
            
            VStack {
                Rectangle().foregroundColor(.blue)
                .frame(width: 150, height: 150)
                .position(self.position2)
                .gesture(drag2)
                .clipped()
            }
            .background(Color.yellow)
            .frame(width: dragArea2.width, height: dragArea2.height)
        }
        
    }
}
关于如何在任何容器之外保持拖动禁用的任何想法,如已经实现的那样,但也允许在每个容器的完整范围内拖动,而不管其他容器发生了什么?

最佳答案

这是可能的解决方案。这个想法是在容器坐标空间中具有拖动坐标,如果起始位置超出该命名区域,则忽略拖动。
使用 Xcode 11.4/iOS 13.4 测试
demo

struct ContentView: View {

    @State var position: CGPoint = CGPoint(x: 100, y: 150)
    @State var lastPosition: CGPoint = CGPoint(x: 100, y: 150)

    var body: some View {
        let area = CGRect(x: 0, y: 0, width: 200, height: 300)

        let drag = DragGesture(coordinateSpace: .named("area"))
        .onChanged {
            guard area.contains($0.startLocation) else { return }
            self.position = CGPoint(x: $0.translation.width + self.lastPosition.x, y: $0.translation.height + self.lastPosition.y)
        }
        .onEnded {_ in
            self.lastPosition = self.position
        }

        return VStack {
            Rectangle().foregroundColor(.red)
                .frame(width: 150, height: 150)
                .position(self.position)
                .gesture(drag)
                .clipped()
        }
        .background(Color.green)
        .frame(width: area.size.width, height: area.size.height)
        .coordinateSpace(name: "area")

    }
}

关于ios - 在 SwiftUI 中,如何使手势在容器 View 之外处于非事件状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63049420/

相关文章:

ios - UITextView 上的手势动画

ios - 如何修改 tableView 单元格内 UIView 的大小?

点击另一个 TextField 时,SwiftUI TextField 不会提交更改

iphone - UIScrollview 类似动画的分页

arrays - 如何仅在搜索栏文本不为空时才运行过滤功能?

swift - 删除 SwiftUI 中部分之间的空白

cordova - PhoneGap 捏缩放

ios - Swift 4 - 按下按钮时的 Action - 循环?

iphone - #import of iPhone Frameworks (ALAssetsLibrary.h) 的正确路径

ios - 我如何替换 iOS7 的手机间隙聚光灯图标?