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

查看:19
本文介绍了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?

这是我的主要网格视图:

Here is my main Grid view:

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 上的小摘要:

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...(它是你的应用数据设置的简化版本,但发展的想法和方向应该很清楚)

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天全站免登陆