首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DragGesture与MagnificationGesture在iOS14中SwiftUI视图上的结合

DragGesture与MagnificationGesture在iOS14中SwiftUI视图上的结合
EN

Stack Overflow用户
提问于 2020-12-01 15:07:42
回答 1查看 702关注 0票数 2

我把我的头发拔了出来,我没有找到一个似乎合适的答案。

我有一个视图(见下文)-我需要支持两个手势(拖动和放大),以某种方式在这个控制。视图是一个knob和拖动修改的值,放大被认为是修改旋钮的精度。

我尝试了以下几点:

  • drag.simultanously(with:magnification)做了一个手势,这有点管用,但问题似乎是,当一根手指被提起时,MagnificationGesture还没有结束,因此拖放不会继续--它也永远不会得到.onEnded调用。(我不知道为什么-我会认为这是个窃听器?)其效果是一种相当奇怪的体验,当用户期望改变值时,旋钮仍在放大。
  • 添加了一个似乎在执行drag.onChange.gesture(drag).gesture(magnification),它从不调用drag.onChange块,但出于某种原因只调用了.onEnded。实际上,拖动并不是work...
  • drag.exclusively(before:magnification)与放大、永不结束和传回拖动两者的结合。
  • I还尝试将magnification手势放置在周围的VStack上,并将拖动手势保留在内部Path视图中,但不知怎么的,这似乎也会导致与drag.simultanously(with:magnification)在内部区域的结果相同。我还没有弄清楚如何防止拖动手势在内部视图上传播并与magnification结合。

我将非常感谢反馈,因为我的想法,至少在目前.

代码语言:javascript
复制
struct VirtualKnobView<Content:View>: View {
    
    init(model:VirtualKnobModel, contentSize:CGSize, @ViewBuilder _ contentView:()-> Content ){
        self.model = model
        self.contentSize = contentSize
        self.contentView = contentView()
    }
    
    init(contentSize:CGSize, @ViewBuilder _ contentView:()-> Content){
        self.model = VirtualKnobModel(inner: 0.7, outer: 0.8, ext: 0.05, angle: 30.0)
        self.contentSize = contentSize
        self.contentView = contentView()
    }
    
    @ObservedObject var model:VirtualKnobModel
    
    @State var lastMagnitude:CGFloat = 1.0
    @State var isDragging:Bool = false
    
    var contentSize:CGSize
    var contentView:Content
    
    var body: some View {
        
        let size = model.calclulateSize(for: contentSize)
        
        let drag = DragGesture(minimumDistance: 0)
            .onChanged({ state in
                print ("Drag Changed")
                let point = state.location
                let refPoint = CGPoint(x: (point.x - size/2)/size,
                                       y: (point.y - size/2)/size)
                model.setTouchPoint(point: refPoint)
            })
            .onEnded({ _ in
                print ("Drag ended")
                model.reset()
            })
        
        let magnification = MagnificationGesture()
            .onChanged({ (magnitude:CGFloat) in
                print ("Magnification changed")
                let delta = magnitude / lastMagnitude
                lastMagnitude = magnitude
                let angle = model.clickAngle
                print ("Magnitude: \(magnitude)")
                let magnified = angle * delta
                if magnified >= model.minClick && magnified <= model.maxClick {
                    model.clickAngle = magnified
                }
            })
            .onEnded({ _ in
                print("Magnification ended")
                lastMagnitude = 1.0
                model.reset()
            })
        
        let scaler = CGAffineTransform(scaleX: size, y: size)
        
        let gesture = magnification.simultaneously(with: drag)
        
        ZStack {
            HStack {
                Spacer()
                VStack{
                    Spacer()
                    Path { path in
                        model.segmentList.forEach { segment in
                            let inner = segment.inner
                            let outer = segment.outer
                            let innerScaled = inner.applying(scaler)
                            let outerScaled = outer.applying(scaler)
                            path.move(to: innerScaled)
                            path.addLine(to: outerScaled)
                        }
                        
                    }
                    .stroke(model.strokeColor, lineWidth: model.lineWidth)
                    .background(Color.black)
                    .frame(width: size, height: size)
                    Spacer()
                }
                Spacer()
            }
            .background(Color.black)
            .gesture(gesture)
            
            HStack {
                Spacer()
                VStack{
                    Spacer()
                    contentView
                        .frame(width: contentSize.width,
                               height: contentSize.height,
                               alignment: .center)
                    Spacer()
                }
                Spacer()
            }
        }
    }
}
EN

回答 1

Stack Overflow用户

发布于 2020-12-01 18:55:32

以下是我今天得到的解决方案:

  • ,我能识别,在我的旋钮上拖动,

  • ,我能识别,在周围空旷的空间上放大。(我很幸运)

我没有办法实现我在UiKit上的行为,在这种情况下,夹点和拖动是同时工作的。

如果你碰到路-请告诉我。

有趣的细节:我认为手势只适用于不透明的像素。所以每件事都需要有背景。无法将手势附加到颜色(.clear)或任何不显示的东西上。这让我对路径视图感到有些头疼,因为它只会触发路径实际上画了什么东西的手势。

代码语言:javascript
复制
struct VirtualKnobView<Content:View>: View {
    
    init(model:VirtualKnobModel, contentSize:CGSize, @ViewBuilder _ contentView:()-> Content ){
        self.model = model
        self.contentSize = contentSize
        self.contentView = contentView()
    }
    
    init(contentSize:CGSize, @ViewBuilder _ contentView:()-> Content){
        self.model = VirtualKnobModel(inner: 0.7, outer: 0.8, ext: 0.05, angle: 30.0)
        self.contentSize = contentSize
        self.contentView = contentView()
    }
    
    @ObservedObject var model:VirtualKnobModel
    
    @State var lastMagnitude:CGFloat = 1.0
    @State var isDragging:Bool = false
    
    var contentSize:CGSize
    var contentView:Content
    
    // The bgcolor is needed for the views to receive gestures.
    let bgColor = Color(UIColor.black.withAlphaComponent(0.001))
    
    var body: some View {
        
        let size = model.calclulateSize(for: contentSize)
        
        
        let drag = DragGesture(minimumDistance: 0)
            .onChanged({ state in
                let point = state.location
                let refPoint = CGPoint(x: (point.x - size/2)/size,
                                       y: (point.y - size/2)/size)
                model.setTouchPoint(point: refPoint)
            })
            .onEnded({ _ in
                model.reset()
            })
        
        let magnification = MagnificationGesture()
            .onChanged({ (magnitude:CGFloat) in
                let delta = magnitude / lastMagnitude
                lastMagnitude = magnitude
                let angle = model.clickAngle
                let magnified = angle * delta
                if magnified >= model.minClick && magnified <= model.maxClick {
                    model.clickAngle = magnified
                }
            })
            .onEnded({ _ in
                lastMagnitude = 1.0
                model.reset()
            })
        
        let scaler = CGAffineTransform(scaleX: size, y: size)
        
        ZStack {
            HStack(spacing:0) {
                Rectangle()
                    .foregroundColor(bgColor)
                    .gesture(magnification)
                VStack(spacing:0){
                    Rectangle()
                        .foregroundColor(bgColor)
                    
                    Path { path in
                        model.segmentList.forEach { segment in
                            let inner = segment.inner
                            let outer = segment.outer
                            let innerScaled = inner.applying(scaler)
                            let outerScaled = outer.applying(scaler)
                            path.move(to: innerScaled)
                            path.addLine(to: outerScaled)
                        }
                        
                    }
                    .stroke(model.strokeColor, lineWidth: model.lineWidth)
                    .foregroundColor(bgColor)
                    .gesture(drag)
                    .frame(width: size, height: size)
                    
                    Rectangle()
                        .foregroundColor(bgColor)
                }
                Rectangle()
                    .foregroundColor(bgColor)
                    .gesture(magnification)
            }
            
            HStack {
                Spacer()
                VStack{
                    Spacer()
                    contentView
                        .frame(width: contentSize.width,
                               height: contentSize.height,
                               alignment: .center)
                    Spacer()
                }
                Spacer()
            }
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65093068

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档