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