SwiftUI перетащить жест через несколько подпредставлений - PullRequest
2 голосов
/ 18 января 2020

Я пытаюсь создать сетку из маленьких квадратов, чтобы при наведении на них пальца (или пролистывания) маленькие квадратики временно «всплывали» и тряслись. Затем, если они продолжат долго нажимать на это представление, оно откроет другое представление с дополнительной информацией.

Я подумал, что реализации жеста перетаскивания для квадратных представлений будет достаточно, но похоже, что только одно представление может захватывать жест перетаскивания одновременно.

Есть ли способ включить несколько видов для захвата жеста перетаскивания или способ реализации жеста "зависания" для 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])
        }
      }
  }
}

А вот мой квадратный вид, который будет содержать небольшую сводку для отображения на квадрате:

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 Ответ

1 голос
/ 18 января 2020

Вот демонстрация возможного подхода ... (это упрощенная версия настроек данных вашего приложения, но идея и направление эволюции должны быть ясны)

Основная идея, что вы захватываете перетаскивание не в представлении элемента, но в представлении содержимого, передающем необходимые состояния (или вычисляемые зависимые данные) в представление элемента, когда (или если) необходимо.

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
            })
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...