SwiftUI доступ к представлению, созданному в цикле ForEach - PullRequest
1 голос
/ 08 января 2020

Есть ли способ доступа к представлению, созданному в ForEach l oop? Я создаю представления (Rectangle s) с этой структурой для этого l oop. Я хочу изменить цвет заливки при нажатии жестов.

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, но я не знаю, где они хранятся или как изменить их по клику. Я могу создать функцию, которая возвращает представление (прямоугольник), сохранить их в массиве и отобразить их на экране, но опять же я не знаю, как получить к ним доступ и изменить тот, который мне нужен.

Ответы [ 3 ]

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

Оставьте @State, чтобы отслеживать, какие индексы подсвечены, затем сделайте свой цвет функцией этого состояния. Вот пример с анимацией:

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)
          }
      }
    }
  }
}
1 голос
/ 08 января 2020

вы можете сделать это так:

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)
            }
        }
    }
}
1 голос
/ 08 января 2020

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

В этом случае вы можете иметь DisplayingRect для сохранения свойства цвета, а затем иметь жест касания для каждого Rectangle найдите правильную структуру в вашем массиве rects по идентификатору и измените свойство цвета.

Чтобы отделить logi c от вашего представления и сделать его более тестируемым, вы можете захотеть создать некоторый класс модели представления, который охватывает это, но помещая все это в ваше представление, будет работать без этих преимуществ.

Этот подход может выглядеть примерно так (тестирование локально и работает):

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 вместе с протоколом ObservableObject позволяют представлению обновляться при каждом изменении данных, которые оно использует из viewModel. Чтобы автоматически сигнализировать о свойствах, которые должны вызывать обновление представления sh, используется оболочка свойства @Published.

https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-observedobject-to-manage-state-from-external-objects

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...