Ios SwiftUI访问在ForEach循环中创建的视图
是否有方法访问在ForEach循环中创建的视图?我在这个循环上用这个结构创建视图矩形。我想更改点击手势后矩形的填充颜色Ios SwiftUI访问在ForEach循环中创建的视图,ios,swift,macos,swiftui,Ios,Swift,Macos,Swiftui,是否有方法访问在ForEach循环中创建的视图?我在这个循环上用这个结构创建视图矩形。我想更改点击手势后矩形的填充颜色 struct DisplayingRect:Identifiable { var id = UUID() var width:CGFloat = 0 var height:CGFloat = 0 var xAxis:CGFloat = 0 var yAxis:CGFloat = 0 init(width:CGFloat, he
struct DisplayingRect:Identifiable {
var id = UUID()
var width:CGFloat = 0
var height:CGFloat = 0
var xAxis:CGFloat = 0
var yAxis:CGFloat = 0
init(width:CGFloat, height:CGFloat, xAxis:CGFloat, yAxis:CGFloat) {
self.width = width
self.height = height
self.xAxis = xAxis
self.yAxis = yAxis
}
}
ForEach(self.rects) { rect in
Rectangle()
.fill(Color.init(.sRGB, red: 1, green: 0, blue: 0, opacity: 0.2))
.frame(width: rect.width, height: rect.height)
.offset(x: rect.xAxis, y: rect.yAxis)
.id(rect.id)
.onTapGesture {
print("Clicked")
self.rectTapped = rect.width
print(rect.width)
print(rect.id)
if !self.didTap {
self.didTap = true
} else {
self.didTap = false
}
}
我可以为每个视图分配一个id设置其id属性,但我不知道它们存储在哪里,也不知道单击后如何修改它们。我可以创建一个函数,返回一个视图矩形并将其存储在一个数组中,然后在屏幕上显示它们,但我同样不知道如何访问它们并修改我想要的视图。SwiftUI鼓励使用声明式方法–您不需要而且实际上无法直接访问任何视图来存储对它的引用。可以为您的视图提供数据,只要数据发生更改,视图就会更新 在这种情况下,您可以让DisplayingRect存储颜色属性,然后让每个矩形上的点击手势按ID查找rects数组中的正确结构,并修改颜色属性 为了将逻辑从视图中分离出来并使该单元的更多部分可测试,您可能希望创建某种包含该逻辑的视图模型类,但将其全部放在视图中将无法获得这些好处 这种方法可能类似于本地测试&有效:
struct DisplayingRect: Identifiable {
let id = UUID()
var color = Color.red
var width: CGFloat
var height: CGFloat
var xAxis: CGFloat
var yAxis: CGFloat
init(
width: CGFloat,
height: CGFloat,
xAxis: CGFloat = 0,
yAxis: CGFloat = 0)
{
self.width = width
self.height = height
self.xAxis = xAxis
self.yAxis = yAxis
}
}
final class ContentViewModel: ObservableObject {
@Published
private(set) var rects: [DisplayingRect] = [
.init(width: 100, height: 100),
.init(width: 100, height: 100),
.init(width: 100, height: 100)
]
func didTapRectangle(id: UUID) {
guard let rectangleIndex = rects.firstIndex(where: { $0.id == id }) else {
return
}
rects[rectangleIndex].color = .blue
}
}
struct ContentView: View {
@ObservedObject
var viewModel = ContentViewModel()
var body: some View {
VStack {
ForEach(viewModel.rects) { rect in
Rectangle()
.fill(rect.color)
.frame(width: rect.width, height: rect.height)
.offset(x: rect.xAxis, y: rect.yAxis)
.onTapGesture {
self.viewModel.didTapRectangle(id: rect.id)
}
}
}
}
}
在这种情况下,@ObservedObject属性包装器和observeObject协议允许视图在其从viewModel使用的数据发生更改时更新自身。若要自动向应导致视图刷新的属性发送信号,请使用@Published属性包装器
SwiftUI鼓励使用声明式方法——您不需要而且实际上无法直接访问任何视图来存储对它的引用。可以为您的视图提供数据,只要数据发生更改,视图就会更新 在这种情况下,您可以让DisplayingRect存储颜色属性,然后让每个矩形上的点击手势按ID查找rects数组中的正确结构,并修改颜色属性 为了将逻辑从视图中分离出来并使该单元的更多部分可测试,您可能希望创建某种包含该逻辑的视图模型类,但将其全部放在视图中将无法获得这些好处 这种方法可能类似于本地测试&有效:
struct DisplayingRect: Identifiable {
let id = UUID()
var color = Color.red
var width: CGFloat
var height: CGFloat
var xAxis: CGFloat
var yAxis: CGFloat
init(
width: CGFloat,
height: CGFloat,
xAxis: CGFloat = 0,
yAxis: CGFloat = 0)
{
self.width = width
self.height = height
self.xAxis = xAxis
self.yAxis = yAxis
}
}
final class ContentViewModel: ObservableObject {
@Published
private(set) var rects: [DisplayingRect] = [
.init(width: 100, height: 100),
.init(width: 100, height: 100),
.init(width: 100, height: 100)
]
func didTapRectangle(id: UUID) {
guard let rectangleIndex = rects.firstIndex(where: { $0.id == id }) else {
return
}
rects[rectangleIndex].color = .blue
}
}
struct ContentView: View {
@ObservedObject
var viewModel = ContentViewModel()
var body: some View {
VStack {
ForEach(viewModel.rects) { rect in
Rectangle()
.fill(rect.color)
.frame(width: rect.width, height: rect.height)
.offset(x: rect.xAxis, y: rect.yAxis)
.onTapGesture {
self.viewModel.didTapRectangle(id: rect.id)
}
}
}
}
}
在这种情况下,@ObservedObject属性包装器和observeObject协议允许视图在其从viewModel使用的数据发生更改时更新自身。若要自动向应导致视图刷新的属性发送信号,请使用@Published属性包装器
保持@状态以跟踪高亮显示的索引,然后使颜色成为该状态的函数。下面是一个动画示例:
struct ContentView: View {
@State private var selectedIndices = Set<Int>()
var body: some View {
ForEach (0..<3) { index in
Color(self.selectedIndices.contains(index) ? .yellow : .blue)
.frame(width: 200, height: 200)
.animation(.easeInOut(duration: 0.25))
.onTapGesture {
if self.selectedIndices.contains(index) {
self.selectedIndices.remove(index)
} else {
self.selectedIndices.insert(index)
}
}
}
}
}
保持@状态以跟踪高亮显示的索引,然后使颜色成为该状态的函数。下面是一个动画示例:
struct ContentView: View {
@State private var selectedIndices = Set<Int>()
var body: some View {
ForEach (0..<3) { index in
Color(self.selectedIndices.contains(index) ? .yellow : .blue)
.frame(width: 200, height: 200)
.animation(.easeInOut(duration: 0.25))
.onTapGesture {
if self.selectedIndices.contains(index) {
self.selectedIndices.remove(index)
} else {
self.selectedIndices.insert(index)
}
}
}
}
}
您可以这样做:
struct DisplayingRect:Identifiable, Hashable {
static var counter = 0
var id : Int = DisplayingRect.counter
var width:CGFloat = 0
var height:CGFloat = 0
var xAxis:CGFloat = 0
var yAxis:CGFloat = 0
var color: Color = Color.red
init(width:CGFloat, height:CGFloat, xAxis:CGFloat, yAxis:CGFloat) {
self.width = width
self.height = height
self.xAxis = xAxis
self.yAxis = yAxis
DisplayingRect.counter = DisplayingRect.counter + 1
}
}
struct ContentView : View {
@State var rects : [DisplayingRect] = [
DisplayingRect(width: 30, height: 30, xAxis: 0, yAxis: 0),
DisplayingRect(width: 50, height: 50, xAxis: 50, yAxis: 50)
]
func setColorToID(_ id: Int) {
rects[id].color = Color.blue
}
var body: some View {
ForEach(self.rects, id: \.self) { rect in
Rectangle()
.fill(rect.color)
.frame(width: rect.width, height: rect.height)
.offset(x: rect.xAxis, y: rect.yAxis)
.id(rect.id)
.onTapGesture {
print(rect.id)
self.setColorToID(rect.id)
}
}
}
}
您可以这样做:
struct DisplayingRect:Identifiable, Hashable {
static var counter = 0
var id : Int = DisplayingRect.counter
var width:CGFloat = 0
var height:CGFloat = 0
var xAxis:CGFloat = 0
var yAxis:CGFloat = 0
var color: Color = Color.red
init(width:CGFloat, height:CGFloat, xAxis:CGFloat, yAxis:CGFloat) {
self.width = width
self.height = height
self.xAxis = xAxis
self.yAxis = yAxis
DisplayingRect.counter = DisplayingRect.counter + 1
}
}
struct ContentView : View {
@State var rects : [DisplayingRect] = [
DisplayingRect(width: 30, height: 30, xAxis: 0, yAxis: 0),
DisplayingRect(width: 50, height: 50, xAxis: 50, yAxis: 50)
]
func setColorToID(_ id: Int) {
rects[id].color = Color.blue
}
var body: some View {
ForEach(self.rects, id: \.self) { rect in
Rectangle()
.fill(rect.color)
.frame(width: rect.width, height: rect.height)
.offset(x: rect.xAxis, y: rect.yAxis)
.id(rect.id)
.onTapGesture {
print(rect.id)
self.setColorToID(rect.id)
}
}
}
}