swiftui_在SwiftUI中触摸事件
swiftui
SwiftUI is a very new and rapidly evolving framework — which is great, but that also means it lacks lots of nice features, including touch events.
SwiftUI是一个非常新的且发展Swift的框架-很棒,但是这也意味着它缺少很多不错的功能,包括触摸事件。
So what’s a touch event? If you’re coming from UIKit, you’re probably familiar with them. Really, they’re just a fancy way of saying “Press detected!”
那么什么是触摸事件? 如果您来自UIKit,则可能对它们很熟悉。 确实,它们只是说“检测到压力!”的一种奇特方式。
However, because iPhones and iPads are advanced, multitouch-capable devices, sometimes “Press detected!” isn’t enough. You might want to detect when the user first touches down or maybe when they release … or maybe when they drag and release.
但是,由于iPhone和iPad是先进的,具有多点触控功能的设备,因此有时会“检测到按下!” 还不够 您可能想要检测用户何时首次降落或何时释放……或何时拖动并释放。
Back in the UIKit storyboard, these touch events were easy to handle. UIButton
s came with a huge list of touch events, including Touch Up Inside
, Touch Down
, Touch Up Outside
… there were a lot more, and all together they could receive every action your finger could perform.
回到UIKit故事板上,这些触摸事件很容易处理。 UIButton
带有大量的触摸事件,包括Touch Up Inside
, Touch Down
, Touch Up Outside
………还有更多,并且它们一起可以接收您的手指可以执行的所有操作 。
But what about SwiftUI? Uh … not so much. By default, you only get one touch event: Touch Up Inside
.
但是SwiftUI呢? 呃……不多。 默认情况下,您只会获得一个触摸事件: Touch Up Inside
。
This means the button action will only be called when both these conditions are met:
这意味着仅当同时满足以下两个条件时,才会调用按钮动作:
-
The user lifted their finger
用户举起手指
-
The user’s finger was inside the bounds of the button when lifted
用户的手指在里面 解除按钮的边界
In today’s apps, Touch Up Inside
is the most common touch event used because it gives the user time to cancel. If they decide they don’t want to press the button, all they need to do is drag their finger away — an easy way out.
在当今的应用程序中,“ Touch Up Inside
是最常用的触摸事件,因为它使用户有时间取消。 如果他们决定不想按该按钮,则只需将手指移开即可,这是一种简便的方法。
So it makes sense that SwiftUI’s buttons only support Touch Up Inside
straight out of the box … but what if you want to access all the other touch events?
因此,SwiftUI的按钮仅直接支持“ Touch Up Inside
是有道理的……但是,如果您想访问所有其他触摸事件,该怎么办?
Let’s say you’re making a racing game where there’s a gas pedal. When pressed, the car should go faster. When released, it should slow down. This requires three touch events — Touch Down
, Touch Up Inside
, and Touch Up Outside
. (There’s no Touch Up
touch event, but Touch Up Inside
and Touch Up Outside
combined have the same effect.)
假设您正在制作有油门踏板的赛车游戏。 按下时,汽车应该走得更快。 释放时,它应该变慢。 这需要三个触摸事件- Touch Down
Touch Up Inside
Touch Up Outside
Touch Up Inside
Touch Up Outside
。 (没有“ Touch Up
触摸”事件,但是“ Touch Up Inside
和“ Touch Up Outside
组合具有相同的效果。)
But if SwiftUI’s buttons only support Touch Up Inside
, how are you supposed to make these racing games? Of course, you could heavily sacrifice UX and go with a toggling button — press to accelerate, press to slow down, and then press to accelerate again:
但是,如果SwiftUI的按钮仅支持Touch Up Inside
, 那么您应该如何制作这些赛车游戏? 当然,您可能会严重牺牲UX并使用切换按钮-按加速,按减速,然后按再次加速:
Or you can additionally sacrifice the UI for a multibutton approach:
或者,您也可以牺牲UI以使用多按钮方法:
More buttons, more better! Right? Wait … it looks terrible!
更多按钮,更好! 对? 等等……看起来太糟糕了!
SwiftUI仅对游戏不利吗? (Is SwiftUI Just Bad for Games?)
It could be that SwiftUI isn’t good for games. Maybe it just doesn’t like complex touch events. Maybe it’s time to go back to UIKit.
SwiftUI可能不适用于游戏。 也许只是不喜欢复杂的触摸事件。 也许是时候回到UIKit了。
No, SwiftUI isn’t bad for games. It has no problem with complex touch events. It’s also certainly not the time to go back to UIKit. Apple knew SwiftUI would take time to catch up to UIKit’s level of functionality, so they made it easy to customize with view modifiers. In this article, we’ll use view modifiers to replicate touch events, powered by built-in gestures.
没有, SwiftUI对于游戏来说还不错。 复杂的触摸事件没有问题。 当然也不是时候回到UIKit了。 苹果公司知道SwiftUI会花一些时间来赶上UIKit的功能水平,因此他们使使用视图修饰符进行自定义变得容易。 在本文中,我们将使用视图修饰符复制由内置手势支持的触摸事件。
我们的演示游戏 (Our Demo Game)
Making a racing game would take too much time, but we can scrape it down to the bare minimum — all we need is:
制作赛车游戏会花费太多时间,但是我们可以将其刮到最低限度—我们需要的是:
- A property that keeps track of the gas pedal’s state 跟踪油门踏板状态的属性
- A button 一个按钮
- A label that displays the gas pedal’s state 显示油门踏板状态的标签
That’s not too much, so let’s first stick with the default Touch Up Inside
and make a button that toggles the pressed/released state.
这还不算太多,所以我们首先坚持使用默认的“ Touch Up Inside
并创建一个按钮来切换按下/释放状态。
Here’s the code:
这是代码:
In this alternative, the logic works fine — pressing the button toggles the pressed/released state — but it’s not a great user experience. The button doesn’t have only one purpose — it alternates between two. That means someone might accidentally brake instead of accelerate, costing them their game — and costing you a bad review.
在此替代方案中,逻辑工作正常-按下按钮可切换按下/释放状态-但这并不是很好的用户体验。 该按钮不仅具有一个用途,而且在两个用途之间交替显示。 这意味着某人可能会不小心刹车而不是加速,从而使他们付出了代价,并给您带来了不好的评价。
That’s why touch events would work great here: Press down to accelerate and release to slow down. Touch down, touch up. Let’s recreate those touch events in SwiftUI! We can achieve this using view modifiers and gestures:
这就是触摸事件在这里效果很好的原因:按下可加速,放开可减速。 向下触摸,向上触摸。 让我们在SwiftUI中重新创建那些触摸事件! 我们可以使用视图修饰符和手势来实现:
And because we don’t care about the difference between Touch Up Inside
and Touch Up Outside
(both should release the gas pedal), we can combine them into one .onEnded
block! Now, replace the original toggling button with this:
而且由于我们不在乎“ Touch Up Inside
和“ Touch Up Outside
之间的区别(两者都应释放油门踏板),因此我们可以将它们组合成一个.onEnded
块! 现在,用以下命令替换原始的切换按钮:
Instead of using Button
, we’re going to use a normal Text
label (view modifiers work on all SwiftUI views)! Here’s the result:
而不是使用Button
,我们将使用普通的Text
标签(视图修饰符可在所有SwiftUI视图上使用)! 结果如下:
You can’t tell in the GIF, but the label changes to “Gas pedal pressed!” when I press the button, and “Gas pedal not pressed!” when I release. But that’s a problem. Unlike the default Button
, we don’t get a free indicator that the button’s being pressed.
您无法在GIF中分辨出来,但标签会变为“踩油门!” 当我按下按钮时,并且“未踩下油门踏板!” 当我释放。 但这是一个问题。 与默认的Button
不同,我们没有免费的指示器表明该按钮已被按下。
This is solved easily! We can add another view modifier (this time a built-in one) that changes its scale.
这很容易解决! 我们可以添加另一个视图修改器(这次是内置视图修改器)来更改其比例。
Here’s the result:
结果如下:
One last thing: Have you noticed how SwiftUI’s built-in view modifiers, like .scaleEffect
, look like this?
最后一件事:您是否注意到SwiftUI的内置视图修饰符(如.scaleEffect
)是什么样子?
.scaleEffect(buttonPressed ? 0.9 : 1)
Here’s some more built-in view modifiers.
这是一些更多的内置视图修饰符。
.foregroundColor(Color.white)
.padding(10)
.background(Color.gray)
.cornerRadius(6)
.padding(10)
And then there’s our custom-view modifier, which looks like this:
然后是我们的自定义视图修饰符,如下所示:
.modifier(TouchDownUpEventModifier(changeState: { (buttonState) in
...
logic
...}))
Why does our custom-view modifier need to be wrapped in a .modifier
method, while the built-in ones don’t?
为什么我们的custom-view修饰符需要用.modifier
方法包装,而内置的不需要?
That’s because all the built-in view modifiers are … built-in. To make our custom-view modifier look like the built-in ones, we must make it an extension of View
.
这是因为所有内置的视图修饰符都是…内置的。 为了使我们的custom-view修饰符看起来像内置修饰符,我们必须使其成为View
的扩展。
Now, we can use it like this!
现在,我们可以像这样使用它了!
Looks much cleaner. Great!
看起来更干净。 大!
结论 (Conclusion)
It’s never a good idea to have too many buttons, or buttons that serve multiple purposes. Instead, use touch events for consistency and ease of use. Touch events aren’t built into SwiftUI, but you can replicate them using view modifiers and gestures. You can also wrap your custom view modifier into an extension to make it easier to use.
有太多的按钮或具有多种用途的按钮绝不是一个好主意。 相反,请使用触摸事件以保持一致性和易用性。 触摸事件未内置到SwiftUI中,但您可以使用视图修饰符和手势来复制它们。 您还可以将自定义视图修饰符包装到扩展中,以使其易于使用。
Thanks for reading!
谢谢阅读!
翻译自: https://medium.com/better-programming/implement-touch-events-in-swiftui-b3a2b0700fd4
swiftui