Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swiftui 如何使用LongPress手势并与计时器结合使用‘;泵&x27;模型的价值观?_Swiftui_Combine - Fatal编程技术网

Swiftui 如何使用LongPress手势并与计时器结合使用‘;泵&x27;模型的价值观?

Swiftui 如何使用LongPress手势并与计时器结合使用‘;泵&x27;模型的价值观?,swiftui,combine,Swiftui,Combine,这是给MacOS的。我试图弄清楚,当用户按下一个自定义按钮时,我如何向我的模型输出值。基本上,我正在尝试创建一个MouseDown/MouseUp组合,中间有一个计时器。仅仅一个长按手势似乎是不可能的,所以我一直在尝试联合收割机和定时器,但只取得了部分成功。我有以下资料: import SwiftUI import Combine var cancellable: Cancellable? struct ContentView: View { var body: some View

这是给MacOS的。我试图弄清楚,当用户按下一个自定义按钮时,我如何向我的模型输出值。基本上,我正在尝试创建一个MouseDown/MouseUp组合,中间有一个计时器。仅仅一个长按手势似乎是不可能的,所以我一直在尝试联合收割机和定时器,但只取得了部分成功。我有以下资料:

import SwiftUI
import Combine

var cancellable: Cancellable?

struct ContentView: View {
    var body: some View {
        ZStack{
            FastForwardButton().frame(width: 40, height: 40)
        }.frame(width: 200, height: 200)
    }
}

struct FastForwardButton: View {
    var timer = Timer.publish(every: 0.2, on: .main, in: .common)
    @GestureState private var isPressed = false
   // @State var cancellable: Cancellable?

    var body: some View {
        Rectangle()
            .gesture(
                LongPressGesture(minimumDuration: 4)
                    .updating($isPressed, body: { (currentState, state, transaction) in
                        if self.isPressed == false{
                            state = currentState
                            print("Timer Started")
                            cancellable = self.timer.connect()
                        }
                    })
            )

         .onReceive(timer) { time in
            // Do Something here eg myModel.pump()
            print("The time is \(time)")
            if self.isPressed == false{
                print("Timer Cancelled")
                cancellable?.cancel()
              //  cancellable = nil
            }
        }
    }
}

上述方法只适用一次。我得到:

“计时器已启动”
“时间是xxx”
..…
“时间是xxx”
“计时器已取消”

但我刚刚得到的第二份新闻:
“计时器已启动”

没有进一步的行动

注意,我还必须临时将引用移动到视图外部的Cancelable,因为我在更新时收到了关于修改视图的警告

有人能找出.onReceive闭包只调用一次的原因吗?谢谢

试试这个(复制-粘贴-运行)macOS

它显示两个按钮,您可以开始停止发布。。。(Apperi是正确的,一旦取消发布服务器,它将无法再次使用。这对于任何发布服务器都是正确的,对于Timer.publisher来说不是特别的

如果您想“发布”模型中的某些更改,可以采用标准方式

func start() {
    timerPublisher = Timer.publish(every: 0.5, on: RunLoop.main, in: .default)
    handle = timerPublisher?.sink(receiveValue: {
        print($0)
        self.objectWillChange.send()
    })
    startstop = timerPublisher?.connect()
    print("start")
}
问题是为什么不简单地使用.autoconnect()?答案是灵活性,考虑一下这个模型

class Model: ObservableObject {
    var timerPublisher: Timer.TimerPublisher?
    var handle: AnyCancellable?
    var startstop: Cancellable?
    func createTimerPublisher() {
        timerPublisher = Timer.publish(every: 0.5, on: RunLoop.main, in: .default)
        handle = timerPublisher?.sink(receiveValue: {
            print($0)
            self.objectWillChange.send()
        })
    }
    init() {
        createTimerPublisher()
    }
    func start() {
        startstop = timerPublisher?.connect()
        print("start")
    }
    func stop() {
        startstop?.cancel()
        print("stop")
        // or create it conditionaly for later use
        createTimerPublisher()
    }
}
更新鼠标在某些视图上的上下移动启动/停止计时器的位置

import SwiftUI
import Combine

class Model: ObservableObject {
    var timerPublisher: Timer.TimerPublisher?
    var handle: AnyCancellable?
    var startstop: Cancellable?
    func createTimerPublisher() {
        timerPublisher = Timer.publish(every: 0.5, on: RunLoop.main, in: .default)
        handle = timerPublisher?.sink(receiveValue: {
            print($0)
            self.objectWillChange.send()
        })
    }
    init() {
        createTimerPublisher()
    }
    func start() {
        // if
        startstop = timerPublisher?.connect()
        print("start")
    }
    func stop() {
        startstop?.cancel()
        startstop = nil
        print("stop")
        // or create it conditionaly for later use
        createTimerPublisher()
    }
}

struct ContentView: View {
    @ObservedObject var model = Model()
    var body: some View {
        VStack {
            Button(action: {
                self.model.start()
            }) {
                Text("Start")
            }
            Button(action: {
                self.model.stop()
            }) {
                Text("Stop")
            }
            MouseUpDownRepresentable(content: Rectangle()).environmentObject(model)
            .frame(width: 50, height: 50)
        }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

class MouseUpDownViewClass<Content>: NSHostingView<Content> where Content : View {
    let model: Model
    required init(model: Model, rootView: Content) {
        self.model = model
        super.init(rootView: rootView)
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    required init(rootView: Content) {
        fatalError("init(rootView:) has not been implemented")
    }

    override func mouseUp(with event: NSEvent) {
        print("mouse up")
        model.stop()
    }
    override func mouseDown(with event: NSEvent) {
        print("mouse down")
        model.start()
    }
}

struct MouseUpDownRepresentable<Content>: NSViewRepresentable where Content: View {
    @EnvironmentObject var model: Model
    let content: Content

    func makeNSView(context: Context) -> NSHostingView<Content> {
        return MouseUpDownViewClass(model: model, rootView: self.content)
    }

    func updateNSView(_ nsView: NSHostingView<Content>, context: Context) {
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

计时器不可更新,一旦失效/取消,将无法再次使用。有关可能的解决方案,请参阅主题。好的,谢谢。我将根据您的示例尝试每次鼠标向下重新创建计时器谢谢,但这不是我想要的。我基本上希望在SwiftUI上启动计时器,相当于鼠标向下,然后在鼠标u上再次停止计时器p、 问题是什么?鼠标按下->开始,鼠标向上->停止…@Peter您在鼠标按下,鼠标向下事件方面有问题吗?这是完全不同的问题,可以使用中描述的类似方法解决,或者只需检查NSHostingView(您可以跟踪鼠标事件)@Peter用鼠标上/下更新来启动/停止计时器publisherThank you user3441734。我最初的评论是因为你使用了不同的按钮来启动和停止计时器,但是你更新的答案,特别是最后一个,对我的情况非常有效。我以前确实尝试过Dragesture,但从未完全成功。再次感谢!
import SwiftUI
import Combine

class Model: ObservableObject {
    var timerPublisher: Timer.TimerPublisher?
    var handle: AnyCancellable?
    var startstop: Cancellable?
    func createTimerPublisher() {
        timerPublisher = Timer.publish(every: 0.5, on: RunLoop.main, in: .default)
        handle = timerPublisher?.sink(receiveValue: {
            print($0)
            self.objectWillChange.send()
        })
    }
    init() {
        createTimerPublisher()
    }
    func start() {
        // if
        startstop = timerPublisher?.connect()
        print("start")
    }
    func stop() {
        startstop?.cancel()
        startstop = nil
        print("stop")
        // or create it conditionaly for later use
        createTimerPublisher()
    }
}

struct ContentView: View {
    @ObservedObject var model = Model()
    var body: some View {
        VStack {
            Button(action: {
                self.model.start()
            }) {
                Text("Start")
            }
            Button(action: {
                self.model.stop()
            }) {
                Text("Stop")
            }
            MouseUpDownRepresentable(content: Rectangle()).environmentObject(model)
            .frame(width: 50, height: 50)
        }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

class MouseUpDownViewClass<Content>: NSHostingView<Content> where Content : View {
    let model: Model
    required init(model: Model, rootView: Content) {
        self.model = model
        super.init(rootView: rootView)
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    required init(rootView: Content) {
        fatalError("init(rootView:) has not been implemented")
    }

    override func mouseUp(with event: NSEvent) {
        print("mouse up")
        model.stop()
    }
    override func mouseDown(with event: NSEvent) {
        print("mouse down")
        model.start()
    }
}

struct MouseUpDownRepresentable<Content>: NSViewRepresentable where Content: View {
    @EnvironmentObject var model: Model
    let content: Content

    func makeNSView(context: Context) -> NSHostingView<Content> {
        return MouseUpDownViewClass(model: model, rootView: self.content)
    }

    func updateNSView(_ nsView: NSHostingView<Content>, context: Context) {
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
struct TouchView: View {
    @State var pressed = false
    var body: some View {
        Circle().fill(pressed ? Color.yellow : Color.orange)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged({ (touch) in
                        if self.pressed == false {
                            self.pressed = true
                            print("start")
                        }
                    })
                    .onEnded({ (touch) in
                        print("stop")
                        self.pressed = false
                    })
            )
    }
}