跨多个子视图的 SwiftUI 拖动手势
Posted
技术标签:
【中文标题】跨多个子视图的 SwiftUI 拖动手势【英文标题】:SwiftUI drag gesture across multiple subviews 【发布时间】: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
)
【问题讨论】:
【参考方案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
)以及任何动画信息?以上是关于跨多个子视图的 SwiftUI 拖动手势的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法在 SwiftUI 中复制手势或处理它们并将它们传递给子视图?