跨多个子视图的SwiftUI拖动手势 [英] SwiftUI drag gesture across multiple subviews

查看:44
本文介绍了跨多个子视图的SwiftUI拖动手势的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm attempting to create a grid of small square views, that when the user hovers over them with their thumb (or swipes across them), the little squares will temporarily "pop up" and shake. Then, if they continue to long press on that view, it would open up another view with more information.

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

I thought that implementing a drag gesture on the square views would be enough, but it looks like only one view can capture a drag gesture at a time.

是否可以使多个视图捕获拖动手势,或者是否可以为iOS实现悬停"手势?

Is there way to enable multiple views to capture a drag gesture, or a way to implement a "hover" gesture for 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视图,其中将包含一个小的摘要以显示在正方形上:

And here is my Square view that would hold a small summary to display on the 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
      })

  }
}

推荐答案

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

Here is a demo of possible approach... (it is simplified version of your app data settings, but the idea and direction where to evolve should be clear)

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

The main idea that you capture drag not in item view but in the content view transferring needed states (or calculable dependent data) into item view when (or if) needed.

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

这篇关于跨多个子视图的SwiftUI拖动手势的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆