【问题标题】:SwiftUI drag gesture across multiple subviews跨多个子视图的 SwiftUI 拖动手势
【发布时间】:2020-01-18 06:02:55
【问题描述】:

我正在尝试创建一个由小方块视图组成的网格,当用户用拇指将鼠标悬停在它们上方(或在它们上滑动)时,小方块会暂时“弹出”并摇晃。然后,如果他们继续长按该视图,它将打开另一个包含更多信息的视图。

我认为在方形视图上实现拖动手势就足够了,但看起来一次只有一个视图可以捕获拖动手势。

有没有办法让多个视图捕捉拖动手势,或者为 iOS 实现“悬停”手势?

这是我的主网格视图:

import SwiftUI

struct ContentView: View {
  @EnvironmentObject var data: PlayerData

    var body: some View {
      VStack {
        HStack {
      PlayerView(player: self.data.players[0])
      PlayerView(player: self.data.players[1])
      PlayerView(player: self.data.players[2])
        }

        HStack {
      PlayerView(player: self.data.players[3])
      PlayerView(player: self.data.players[4])
      PlayerView(player: self.data.players[5])
        }

        HStack {
      PlayerView(player: self.data.players[6])
      PlayerView(player: self.data.players[7])
      PlayerView(player: self.data.players[8])
        }

        HStack {
      PlayerView(player: self.data.players[9])
      PlayerView(player: self.data.players[10])
        }
      }
  }
}

这是我的 Square 视图,其中包含一个小摘要以显示在 Square 上:

import SwiftUI

struct PlayerView: View {
  @State var scaleFactor: CGFloat = 1.0
  var player: Player = Player(name: "Phile", color: .green, age: 42)

    var body: some View {
      ZStack(alignment: .topLeading) {
        Rectangle().frame(width: 100, height: 100).foregroundColor(player.color).cornerRadius(15.0).scaleEffect(self.scaleFactor)

        VStack {
          Text(player.name)
          Text("Age: \(player.age)")
        }.padding([.top, .leading], 10)
      }.gesture(DragGesture().onChanged { _ in
        self.scaleFactor = 1.5
      }.onEnded {_ in
        self.scaleFactor = 1.0
      })

  }
}

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

    这里是一个可能的方法的演示......(它是您的应用数据设置的简化版本,但应该明确的想法和发展方向)

    主要思想不是在项目视图中捕获拖动,而是在内容视图中在需要时(或如果)将所需状态(或可计算的相关数据)传输到项目视图中。

    struct PlayerView: View {
        var scaled: Bool = false
        var player: Player = Player(name: "Phile", color: .green, age: 42)
    
        var body: some View {
            ZStack(alignment: .topLeading) {
                Rectangle().frame(width: 100, height: 100).foregroundColor(player.color).cornerRadius(15.0).scaleEffect(scaled ? 1.5 : 1)
    
                VStack {
                    Text(player.name)
                    Text("Age: \(player.age)")
                }.padding([.top, .leading], 10)
            }.zIndex(scaled ? 2 : 1)
        }
    }
    
    
    struct ContentView: View {
        @EnvironmentObject var data: PlayerData
    
        @GestureState private var location: CGPoint = .zero
        @State private var highlighted: Int? = nil
    
        private var Content: some View {
            VStack {
                HStack {
                    ForEach(0..<3) { i in
                        PlayerView(scaled: self.highlighted == i, player: self.data.players[i])
                            .background(self.rectReader(index: i))
                    }
                }
                .zIndex((0..<3).contains(highlighted ?? -1) ? 2 : 1)
    
                HStack {
                    ForEach(3..<6) { i in
                        PlayerView(scaled: self.highlighted == i, player: self.data.players[i])
                            .background(self.rectReader(index: i))
                    }
                }
                .zIndex((3..<6).contains(highlighted ?? -1) ? 2 : 1)
            }
        }
    
        func rectReader(index: Int) -> some View {
            return GeometryReader { (geometry) -> AnyView in
                if geometry.frame(in: .global).contains(self.location) {
                    DispatchQueue.main.async {
                        self.highlighted = index
                    }
                }
                return AnyView(Rectangle().fill(Color.clear))
            }
        }
    
        var body: some View {
            Content
            .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global)
                .updating($location) { (value, state, transaction) in
                    state = value.location
                }.onEnded {_ in
                    self.highlighted = nil
                })
        }
    }
    

    【讨论】:

    • 我只是想用你的回答澄清一些事情,因为我对 swift 还很陌生,而且苹果文档似乎没有多大帮助......打电话给.background()在每个PlayerView 上都有一个View,这就是为什么我们可以给它一个GeometryReader 视图。 GeometryReader 视图捕获直接父几何图形,在这种情况下是 PlayerView 而不是 ContentView,对吗?以及对updating 的调用,value, state, transaction 参数是新值、与当前值的绑定(所以是$location)以及任何动画信息?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 2021-03-16
    相关资源
    最近更新 更多