SwiftUI - Struct Binding не обновляет пользовательский интерфейс должным образом - PullRequest
2 голосов
/ 28 мая 2020

У меня есть вопрос SwiftUI, на который нет ответа или дубликат другой проблемы, а SwiftUI довольно новый.

Следующий код, насколько я понимаю, показывает переключение фона кнопки контроль. Количество лайков увеличивается, как и ожидалось, но изменения состояния, похоже, не передаются в структуру Book.

Все, что я прочитал, - это то, что в предварительном просмотре вам необходимо использовать: .constant(x) внутри представление PreviewProvider.

Однако это не работает, и кнопка с лайками не имеет ни переднего плана, ни цвета фона.

При отладке приложения результат книги понравился действительно меняется. Но цвета переднего плана / фона нет.

Вот код для вида.

import SwiftUI

struct BookDetailView: View {

  @Binding var book: Book
    @State var likes: Int = 0
  var body: some View {
    VStack {

      Text(book.title)
      Image(book.imageName)
        .resizable()
        .aspectRatio(contentMode: .fit)
        .scaledToFit()

        Button(action: {
            self.book.isLiked.toggle()
            self.likes = self.likes + 1
        }) {
            Text("? Like \(likes)")
                .padding()
                .foregroundColor(self.book.isLiked ? .secondary : .primary)
                .background(self.book.isLiked ? Color.rayWenderlichGreen : Color.white)
                .cornerRadius(10)
        }
    }
  }
}

struct BookDetailView_Previews: PreviewProvider {

  static var previews: some View {
    BookDetailView(book: .constant(Book.demoBooks.randomElement()!))
  }
}

Вот настоящая модель книги

import SwiftUI

struct Book: Identifiable {
  var id = UUID()
  var title: String
  var imageName: String
  var isLiked = false
}

extension Book: Equatable {
  static func == (lhs: Book, rhs: Book) -> Bool {
    return lhs.id == rhs.id
  }
}

Я вложил некоторое время, пытаясь понять, почему это происходит, и кажется, что это может быть просто ошибка SwiftUI.

Есть мысли или предложения?

Ответы [ 2 ]

2 голосов
/ 28 мая 2020

Я не могу протестировать, потому что не указан тип Book, но если это структура, должно работать следующее ( примечание: .constant привязка является постоянной, она не изменяет обернутое значение, вам нужен живой )

struct BookDetailView_Previews: PreviewProvider {
  struct TestView: View {
     @State private var book = Book.demoBooks.randomElement()!
     var body: some View {
       BookDetailView(book: $book)
     }
  }
  static var previews: some View {
    TestView()
  }
}

Обновление: теперь с исправлением - причина в том, что сделанная эквивалентная книга не учитывает измененное состояние isLiked, поэтому просмотр не обнаруживает, что что-то изменилось и не обновляется.

Решение состоит в том, чтобы либо удалить это расширение, либо принять во внимание все поля, которые должны указывать измененное значение, как показано ниже

extension Book: Equatable {
  static func == (lhs: Book, rhs: Book) -> Bool {
    lhs.id == rhs.id && lhs.isLiked == rhs.isLiked
  }
}

Протестировано и работает с Xcode 11.4 / iOS 13,4

1 голос
/ 28 мая 2020

Кажется, ваш код в порядке, и ваше понимание, использование и реализация концепции состояния кажутся хорошими.

Странно, что это происходит и со мной. Иногда State var просто не перезагружает представление, и я считаю, что это потому, что SwiftUI нестабилен. У меня есть несколько способов «исправить» это.

  1. Я создаю @State private var toggleMe: Bool! = false и вызываю toggleMe.toggle(), чтобы переключить его всякий раз, когда мне нужно изменить состояние. Это иногда обновляет пользовательский интерфейс
  2. Я прекращаю использовать состояния и создаю собственный объект OberveableObject , как в этом руководстве , потому что тогда я могу вручную сигнализировать, когда состояние изменится, вызывая objectWillChange.send(), и кажется чтобы работать лучше, чем замена State var, по какой-то причине

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

...