SwiftUI:使用 LongPressGesture 显示类似 Pinterest 的上下文菜单
SwiftUI: Using LongPressGesture to display a Pinterest like context menu
我正在尝试在他们的 iOS 应用程序中创建一个类似于 Pinterest 上下文菜单的上下文菜单。长按 post 显示一个四按钮视图,当用户继续长按时,可以拖动和 select 其他按钮。放开长按会 select 您当前正在 select 的任何按钮,或者如果您没有任何 select 则完全关闭菜单。请参阅下面的示例:
到目前为止,我已经在此处尝试了类似于 Apple 文档的内容:
https://developer.apple.com/documentation/swiftui/longpressgesture
但似乎手势一旦达到手势中定义的 minimumDuration 就完成了。我希望手势在用户按住时一直持续,并在他们松开时立即结束。
此外,我在拖动和 selecting 其他按钮时遇到了麻烦。到目前为止,这是我的方法:
struct Example: View {
@GestureState var isDetectingLongPress = false
@State var completedLongPress = false
var longPress: some Gesture {
LongPressGesture(minimumDuration: 3)
.updating($isDetectingLongPress) { currentState, gestureState,
transaction in
gestureState = currentState
transaction.animation = Animation.easeIn(duration: 2.0)
}
.onEnded { finished in
self.completedLongPress = finished
}
}
var body: some View {
HStack {
Spacer()
ZStack {
// Three button array to fan out when main button is being held
Button(action: {
// ToDo
}) {
Image(systemName: "circle.fill")
.frame(width: 70, height: 70)
.foregroundColor(.red)
}
.offset(x: self.isDetectingLongPress ? -90 : 0, y: self.isDetectingLongPress ? -90 : 0)
Button(action: {
// ToDo
}) {
Image(systemName: "circle.fill")
.frame(width: 70, height: 70)
.foregroundColor(.green)
}
.offset(x: 0, y: self.isDetectingLongPress ? -120 : 0)
Button(action: {
// ToDo
}) {
Image(systemName: "circle.fill")
.frame(width: 70, height: 70)
.foregroundColor(.blue)
}
.offset(x: self.isDetectingLongPress ? 90 : 0, y: self.isDetectingLongPress ? -90 : 0)
// Main button
Image(systemName: "largecircle.fill.circle")
.gesture(longPress)
}
Spacer()
}
}
我能找到的最接近的等效项是上下文菜单
Src: AppleDeveloper
如果你按住,你会得到类似的效果。
更新:我找到了一个可行的解决方案,但它使用的是 UIKit,因为我不相信 SwiftUI 提供了一种本机执行此操作的方法。我按照此处找到的类似问题的答案中的指导进行操作:
然而它是用 ObjC 编写的,所以我粗略地翻译成 Swift。对于那些好奇的人,这是该过程的简化版本:
class UIControlsView: UIView {
let createButton = CreateButtonView()
let secondButton = ButtonView(color: .red)
var currentDraggedButton: ButtonView!
required init?(coder: NSCoder) {
fatalError("-")
}
init() {
super.init(frame: .zero)
self.backgroundColor = .green
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(self.longPress))
createButton.addGestureRecognizer(longPress)
createButton.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
createButton.center = CGPoint(x: UIScreen.main.bounds.size.width / 2, y: 40)
secondButton.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
secondButton.center = CGPoint(x: UIScreen.main.bounds.size.width / 2, y: 40)
self.addSubview(secondButton)
self.addSubview(createButton)
}
@objc func longPress(sender: UILongPressGestureRecognizer) {
if sender.state == .began {
print("Started Long Press")
secondButton.center.x = secondButton.center.x + 90
}
if sender.state == .changed {
let location = sender.location(in: self)
guard let superViewLocation = self.superview?.convert(location, from: self) else {
return
}
guard let view = self.superview?.hitTest(superViewLocation, with: nil) else {
return
}
if view.isKind(of: ButtonView.self) {
let touchedButton = view as! ButtonView
if self.currentDraggedButton != touchedButton {
if self.currentDraggedButton != nil {
self.currentDraggedButton.untouchedUp()
}
}
self.currentDraggedButton = touchedButton
touchedButton.isTouchedUp()
} else {
if self.currentDraggedButton != nil {
print("Unsetting currentDraggedButton")
self.currentDraggedButton.untouchedUp()
}
}
}
if sender.state == .ended {
print("Long Press Ended")
let location = sender.location(in: self)
guard let superViewLocation = self.superview?.convert(location, from: self) else {
return
}
guard let view = self.superview?.hitTest(superViewLocation, with: nil) else {
return
}
if view.isKind(of: ButtonView.self) {
let touchedButton = view as! ButtonView
touchedButton.untouchedUp()
touchedButton.tap()
self.currentDraggedButton = nil
}
secondButton.center.x = secondButton.center.x - 90
}
}
我正在尝试在他们的 iOS 应用程序中创建一个类似于 Pinterest 上下文菜单的上下文菜单。长按 post 显示一个四按钮视图,当用户继续长按时,可以拖动和 select 其他按钮。放开长按会 select 您当前正在 select 的任何按钮,或者如果您没有任何 select 则完全关闭菜单。请参阅下面的示例:
到目前为止,我已经在此处尝试了类似于 Apple 文档的内容: https://developer.apple.com/documentation/swiftui/longpressgesture
但似乎手势一旦达到手势中定义的 minimumDuration 就完成了。我希望手势在用户按住时一直持续,并在他们松开时立即结束。
此外,我在拖动和 selecting 其他按钮时遇到了麻烦。到目前为止,这是我的方法:
struct Example: View {
@GestureState var isDetectingLongPress = false
@State var completedLongPress = false
var longPress: some Gesture {
LongPressGesture(minimumDuration: 3)
.updating($isDetectingLongPress) { currentState, gestureState,
transaction in
gestureState = currentState
transaction.animation = Animation.easeIn(duration: 2.0)
}
.onEnded { finished in
self.completedLongPress = finished
}
}
var body: some View {
HStack {
Spacer()
ZStack {
// Three button array to fan out when main button is being held
Button(action: {
// ToDo
}) {
Image(systemName: "circle.fill")
.frame(width: 70, height: 70)
.foregroundColor(.red)
}
.offset(x: self.isDetectingLongPress ? -90 : 0, y: self.isDetectingLongPress ? -90 : 0)
Button(action: {
// ToDo
}) {
Image(systemName: "circle.fill")
.frame(width: 70, height: 70)
.foregroundColor(.green)
}
.offset(x: 0, y: self.isDetectingLongPress ? -120 : 0)
Button(action: {
// ToDo
}) {
Image(systemName: "circle.fill")
.frame(width: 70, height: 70)
.foregroundColor(.blue)
}
.offset(x: self.isDetectingLongPress ? 90 : 0, y: self.isDetectingLongPress ? -90 : 0)
// Main button
Image(systemName: "largecircle.fill.circle")
.gesture(longPress)
}
Spacer()
}
}
我能找到的最接近的等效项是上下文菜单 Src: AppleDeveloper
如果你按住,你会得到类似的效果。
更新:我找到了一个可行的解决方案,但它使用的是 UIKit,因为我不相信 SwiftUI 提供了一种本机执行此操作的方法。我按照此处找到的类似问题的答案中的指导进行操作:
然而它是用 ObjC 编写的,所以我粗略地翻译成 Swift。对于那些好奇的人,这是该过程的简化版本:
class UIControlsView: UIView {
let createButton = CreateButtonView()
let secondButton = ButtonView(color: .red)
var currentDraggedButton: ButtonView!
required init?(coder: NSCoder) {
fatalError("-")
}
init() {
super.init(frame: .zero)
self.backgroundColor = .green
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(self.longPress))
createButton.addGestureRecognizer(longPress)
createButton.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
createButton.center = CGPoint(x: UIScreen.main.bounds.size.width / 2, y: 40)
secondButton.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
secondButton.center = CGPoint(x: UIScreen.main.bounds.size.width / 2, y: 40)
self.addSubview(secondButton)
self.addSubview(createButton)
}
@objc func longPress(sender: UILongPressGestureRecognizer) {
if sender.state == .began {
print("Started Long Press")
secondButton.center.x = secondButton.center.x + 90
}
if sender.state == .changed {
let location = sender.location(in: self)
guard let superViewLocation = self.superview?.convert(location, from: self) else {
return
}
guard let view = self.superview?.hitTest(superViewLocation, with: nil) else {
return
}
if view.isKind(of: ButtonView.self) {
let touchedButton = view as! ButtonView
if self.currentDraggedButton != touchedButton {
if self.currentDraggedButton != nil {
self.currentDraggedButton.untouchedUp()
}
}
self.currentDraggedButton = touchedButton
touchedButton.isTouchedUp()
} else {
if self.currentDraggedButton != nil {
print("Unsetting currentDraggedButton")
self.currentDraggedButton.untouchedUp()
}
}
}
if sender.state == .ended {
print("Long Press Ended")
let location = sender.location(in: self)
guard let superViewLocation = self.superview?.convert(location, from: self) else {
return
}
guard let view = self.superview?.hitTest(superViewLocation, with: nil) else {
return
}
if view.isKind(of: ButtonView.self) {
let touchedButton = view as! ButtonView
touchedButton.untouchedUp()
touchedButton.tap()
self.currentDraggedButton = nil
}
secondButton.center.x = secondButton.center.x - 90
}
}