【问题标题】:SwiftUI: ListItem gesturesSwiftUI:ListItem 手势
【发布时间】: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") })
        }
    }
}

所以...我的问题是:

  1. 使用 SwiftUI 绘制像这里这样的按钮:

我认为解决方案可能与 SwiftUI 组件的新版本有关:LazyHGridOutlineGrouphttps://developer.apple.com/videos/play/wwdc2020/10031

.onDelete() 对我来说不是一个解决方案,因为不可能做 2 个侧边按钮,也不可能编辑“删除”文本

  1. 如何使用 swiftUI 让 2 个手指滑动? (不太重要)

【问题讨论】:

    标签: swift macos swiftui


    【解决方案1】:

    遗憾的是,目前还没有任何原生 SwiftUI 解决方案(截至 SwiftUI 2 beta)。


    您可以使用UIKit 进行自定义滑动操作并将它们包装在UIViewRepresentable 中。

    一些解决方案(您可能已经看过了):


    或者您可以只使用库来代替(至少在开发原生解决方案之前)。

    一些库:


    如果你想实现同时滑动手势,你需要再次使用UIViewRepresentable


    总结

    【讨论】:

      【解决方案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 不支持为多个手指创建手势。唯一的解决方案是将UIViewRepresentableUIPanGestureRecognizer 结合使用。然后你可以将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
      

      它们可以像onMoveonDelete 一样附加到ForEach 容器:

      ForEach {
          // ...
      }
      .swipeActions(edge: .trailing) {
          Button {
              print("Editing...")
          } label: {
              Label("Edit", systemImage: "pencil")
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-22
        • 2020-08-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多