SwiftUI:ListItem 手势
Posted
技术标签:
【中文标题】SwiftUI:ListItem 手势【英文标题】:SwiftUI: ListItem gestures 【发布时间】:2020-06-29 14:25:47 【问题描述】:目标是具有以下行为的修改:
(但只有 2 个按钮 - 左侧 1 个,右侧 1 个)
行为:
短扫显示按钮并让用户能够点击它。
强大的长滑动按钮。
能够使用两指手势
最小的可重现示例:
import SwiftUI
public extension View
func SwiperizeItem(closureL: @escaping () -> (), closureR: @escaping () -> ()) -> some View
self.modifier( SwiperizeItemModifier(closureL: closureL, closureR: closureR) )
struct SwiperizeItemModifier: ViewModifier
@State var dragOffset = CGSize.zero
@State var offset1Shown = CGSize(width: 100, height: 0)
@State var offset1Click = CGSize(width: 250, height: 0)
@State var offset2Shown = CGSize(width: -100, height: 0)
@State var offset2Click = CGSize(width: -250, height: 0)
@State var BackL = Color.green
@State var BackR = Color.red
@State var ForeColorL = Color.white
@State var ForeColorR = Color.white
@State var closureL: () -> Void
@State var closureR: () -> Void
func body(content: Content) -> some View
HStack
Button(action: closureL() )
Text("Left")
.foregroundColor(ForeColorL)
.background(BackL)
.frame(maxWidth: dragOffset.width > 0 ? dragOffset.width : 0)
.fixedSize()
content
//.padding([.leading, .trailing], 20)
.animation(.spring())
.offset(x: self.dragOffset.width)
.gesture(DragGesture()
.onChanged()
value in
self.dragOffset = value.translation
.onEnded()
value in
if ( dragOffset.width > 0 )
if ( dragOffset.width < offset1Shown.width)
self.dragOffset = .zero
else if ( dragOffset.width > offset1Shown.width && dragOffset.width < offset1Click.width )
self.dragOffset = offset1Shown
else if ( dragOffset.width > offset1Click.width )
self.dragOffset = .zero
closureR()
else
if ( dragOffset.width > offset2Shown.width)
self.dragOffset = .zero
else if ( dragOffset.width < offset2Shown.width && dragOffset.width > offset2Click.width )
self.dragOffset = offset2Shown
else if ( dragOffset.width < offset2Click.width )
self.dragOffset = .zero
closureL()
)
// ____________________
struct GuestureItem_Previews: PreviewProvider
static var previews: some View
Group
Text("Hello")
.padding(.all, 30)
.background( Color( NSColor.red ) )
.SwiperizeItem(closureL: print("click left") , closureR: print("click right") )
所以...我的问题是:
-
使用 SwiftUI 绘制像这里这样的按钮:
我认为解决方案可能与 SwiftUI 组件的新版本有关:
LazyHGrid
或OutlineGroup
。 https://developer.apple.com/videos/play/wwdc2020/10031
.onDelete() 对我来说不是一个解决方案,因为不可能做 2 个侧边按钮,也不可能编辑“删除”文本
-
如何使用 swiftUI 让 2 个手指滑动? (不太重要)
【问题讨论】:
【参考方案1】:遗憾的是,目前还没有任何原生 SwiftUI 解决方案(截至 SwiftUI 2 beta)。
SwiftUI - Still no support for custom swipe actions How is possible configure the List "onDelete" action / Button? SwiftUI - List editing mode - how to change delete button title?您可以使用UIKit
进行自定义滑动操作并将它们包装在UIViewRepresentable
中。
一些解决方案(您可能已经看过了):
SwiftUI - Custom Swipe Actions In List Create gesture to edit list item using SwiftUI或者您可以只使用库来代替(至少在开发原生解决方案之前)。
一些库:
SwipeCell (SwiftUI) (可能正是你需要的) SwipeCellKit (UIKit)如果你想实现同时滑动手势,你需要再次使用UIViewRepresentable
:
总结
第一个问题的答案:SwipeCell 第二个问题的答案:SwiftUI: Multitouch gesture / Multiple Gestures【讨论】:
【参考方案2】:“如何实现滑动删除?”
只要您不想为删除按钮创建自定义 UI,您就可以利用 SwiftUI 并使用所有内置功能。
ForEach
有一个名为.onDelete
的修饰符,它为您提供IndexSet
。这表示用户滑动时应删除的行。现在,如果我们实现必要的逻辑并将其包装在动画块中,一切都会按需要进行。
struct ContentView: View
@State var cars = ["Tesla Model 3", "BMW i3", "Roadster", "Cybertruck", "Agera Koenigsegg", "Rimac Concept One"]
var body: some View
NavigationView
List
ForEach(cars, id: \.self) car in
Text(car)
.onDelete indexSet in
withAnimation
cars.remove(atOffsets: indexSet)
.navigationTitle("My Cars")
注意:.onDelete
修饰符不可用于List
,只能应用于ForEach
。
“如何在 SwiftUI 中做出两指滑动手势?”
截至目前,SwiftUI 不支持为多个手指创建手势。唯一的解决方案是将UIViewRepresentable
与UIPanGestureRecognizer
结合使用。然后你可以将minimumNumberOfTouches
设置为2个手指。
来自 Apple 开发者论坛的 post 展示了如何通过简单的 2 指轻击手势实现类似的效果,但滑动的想法和概念非常相似,上面已经解释过。
希望这会有所帮助! ?
【讨论】:
如果要自定义删除ui怎么办? 不幸的是,SwiftUI 2 / Xcode 12 beta 1 不支持自定义 UI 以滑动删除操作。你最好使用 UIKit,而不是在 SwiftUI 中实现一些 hacky 修饰符。 创建这个问题是因为.onDelete()
不是我的解决方案。请再次阅读问题:我需要 2 个带有自定义文本的按钮——一个在右侧,一个在左侧。所以这不是我的问题的答案。
很抱歉我对这个问题的理解很差。作为建议,更好的问题格式可能会吸引更多人回答。关于这个问题,我的建议是只使用 UIKit 和 UIRepresentable,因为 SwiftUI 对您的要求没有任何支持。【参考方案3】:
ios 15
在 iOS 15 中我们终于可以使用原生的Swipe Actions:
func swipeActions<T>(edge: HorizontalEdge = .trailing, allowsFullSwipe: Bool = true, content: () -> T) -> some View where T : View
它们可以像onMove
或onDelete
一样附加到ForEach
容器:
ForEach
// ...
.swipeActions(edge: .trailing)
Button
print("Editing...")
label:
Label("Edit", systemImage: "pencil")
【讨论】:
以上是关于SwiftUI:ListItem 手势的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI - navigationBarBackButtonHidden - 向后滑动手势?
Google AdMob 干扰 SwiftUI 中的摇动手势
SwiftUI - 有没有办法在不覆盖子视图的任何手势的情况下向视图添加手势?