跨多个子视图的SwiftUI拖动手势

时间:2020-01-18 06:02:55

标签: ios swift swiftui

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

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

是否可以使多个视图捕获拖动手势,或者是否可以为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
      })

  }
}

1 个答案:

答案 0 :(得分:4)

以下是可能方法的演示...(它是应用程序数据设置的简化版本,但应明确发展思路和方向)

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

enter image description here

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
            })
    }
}