Использование переменной состояния в логическом операторе в пользовательском интерфейсе Swift

#swift #swiftui

#swift #swiftui

Вопрос:

У меня есть переменная состояния в представлении @State private var value: Int SwiftUI. Когда я использую это состояние в логических операторах, например, so value == 10 , оно не обновляется, если передается во второе представление.

Например, выделение в следующем никогда не меняется:

 struct TestView: View {

   @State private var value = 5
   var body: some View {
    
       Button("update value") {
           withAnimation { value = value   5 }
       }
    
       Text("(value)").padding()

       MyTestView(highlighted: value == 5).padding()
       MyTestView(highlighted: value == 10).padding()
       MyTestView(highlighted: value == 15).padding()
   }
}

struct MyTestView: View {
   @State var highlighted: Bool = false

   var body: some View {
       Text("test")
          .background(highlighted ? Color.red : Color.white)
   }
}
  

Комментарии:

1. ваше второе редактирование вопроса отличается от ночи и дня! какой точный вопрос вы задали!

Ответ №1:

Из документации разработчика Apple:

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

Итак, когда ваше значение, обернутое в состояние, изменяется, тело будет пересчитано. В приведенном выше примере вы не показываете ничего, что могло бы изменить ваше значение состояния. При создании вашего представления в первый раз компилятор проверит первое значение вашей переменной «value», а затем соответствующим образом установит ваш текст. Чтобы внести изменения в этот текст, вам необходимо изменить переменную состояния.

 Button(action: {
    //Here you update your State variable, which will force the body to recalculate
    self.value = 15
})
{
    Text("Update variable")
}
  

Редактировать:

Поскольку вы опубликовали свой код, вот решение. Вам не нужно объявлять highlighted , как State в вашем MyTestView . Просто объявите его как var , и он будет работать. Как говорит Apple, объявите свои значения состояния закрытыми, чтобы не изменять их извне. Здесь, в вашем примере, состояние неверно, потому что вы не изменяете это значение изнутри своего тела.

 struct MyTestView: View {
   var highlighted: Bool = false

   var body: some View {
       Text("test")
          .background(highlighted ? Color.red : Color.white)
   }
}
  

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

Существует решение с использованием привязки, однако это изменит вашу логику и на самом деле не является необходимым в ваших вариантах использования, как обсуждалось в комментарии:

 struct ContentView: View {

    @State private var value = 5
    var body: some View {
    
        Button("update value") {
            withAnimation { value = value   5 }
        }
    
        Text("(value)").padding()

        MyTestView(highlighted: $value, border: 5).padding()
        MyTestView(highlighted: $value, border: 10).padding()
        MyTestView(highlighted: $value, border: 15).padding()
   }
}

struct MyTestView: View {
    @Binding var highlighted: Int
    var border : Int

    var body: some View {
        Text("test")
            .background(highlighted == border ? Color.red : Color.white)
    }
}
  

Даст вам тот же эффект, однако не очень хорошо

Комментарии:

1. @davidev, привязка была бы правильным ответом, а не тем, что вы ответили здесь! это неправильный ответ! Я НЕ знаю, как ваш ответ может быть правильным ответом!

2. @Omid Я не знаю, зачем вам использовать привязку в этом случае. Вы не меняете значение в MyTestView. Из документации Apple: «Используйте привязку для создания двустороннего соединения между свойством, в котором хранятся данные, и представлением, которое отображает и изменяет данные». Если вы хотите изменить значение внутри MyTestView и хотите обновить свой родительский вид, вы бы использовали привязку. Как кнопка переключения, которая отправляет обновления состояния своему родителю

3. @davidev, посмотрите код, который он использует для рендеринга представления, значение == 5, значение == 10, значение == 15! Ваше объяснение привязки не является полным объяснением, загляните на веб-сайт Apple для получения дополнительной информации, если бы он просто вызывал MyTestView вовремя, и после этого не нужно было бы обновлять это представление, я мог бы понять ваш ответ, но, как вы видите, он начинает изменять значение, выделенное в testView! ЭТО ОЗНАЧАЕТ, что MyTestView также должен обновиться! ваше понимание привязки неверно, «для создания двустороннего соединения», которое является частью задания привязки не всех

4. @Omid Я действительно ценю ваши усилия и готов мне помочь! Спасибо большое. Но я должен признать, что показанный мной код — всего лишь пример, демонстрирующий проблему, с которой я столкнулся. На самом деле это действительно так, что вложенное представление не имеет никакого контроля над тем, выделено оно или нет. Вот почему я использовал состояние, а не привязку. Так что в моем конкретном случае я все еще думаю, что это правильный ответ.

5. Также на этой платформе вам лучше принимать быстрые решения. Буквально через час я заметил, что мой первоначальный пример был плохим, и придумал улучшенный. Я получил достаточно запросов на дизлайки и закрытие, чтобы поторопиться, пока он не закрылся ^^