Я пытаюсь изменить Просмотр рейтинга Стюарта Линча, чтобы он поддерживал статическое представление и «элемент управления» для установки рейтинга. Для этого мне нужны некоторые дополнительные свойства для решения двух разных условий. Так
currentRating — текущий рейтинг, позволяющий просмотреть это количество символов.
maxRating — максимально возможный рейтинг и
mutableRating — это привязанный текущий рейтинг, поэтому я могу отображать значение корнета в виде заполненных символов с остатком символов до maxRating незаполненными, а также незаполненным и зачеркнутым символом, чтобы установить рейтинг равным 0.
У меня возникают проблемы с тем, что этот связанный параметр также является необязательным. Я нашел это, которое предполагает, что это возможно, но оно тоже довольно старое. В любом случае, я пробовал различные варианты, как показано в строках с комментариями, пытаясь заставить инициализацию работать, с различными неудачами.
struct RatingView: View {
var currentRating: Int?
var maxRating: Int?
@Binding var mutableRating: Int?
var width:Int
var color: UIColor
var sfSymbol: String
public init(
currentRating: Int? = nil,
maxRating: Int? = nil,
mutableRating: Binding<Int?>,
// mutableRating: Binding<Int>?,
// mutableRating: (Binding<Int>)?,
width: Int = 20,
color: UIColor = .systemYellow,
sfSymbol: String = "star"
) {
self.currentRating = currentRating
self.maxRating = maxRating
self._mutableRating = mutableRating
// self._mutableRating = mutableRating ?? Binding.constant(nil)
self.width = width
self.color = color
self.sfSymbol = sfSymbol
}
public var body: some View {
Text("")
}
}
#Preview ("mutating") {
struct PreviewWrapper: View {
@State var rating: Int? = 3
var body: some View {
RatingView(
maxRating: 5,
mutableRating: $rating,
width: 30,
color: .red,
sfSymbol: "heart"
)
}
}
return PreviewWrapper()
}
#Preview ("non mutating") {
struct PreviewWrapper: View {
var body: some View {
RatingView(
currentRating: 3,
width: 20,
color: .red,
sfSymbol: "heart"
)
}
}
return PreviewWrapper()
}
Итак, мой первый вопрос: могу ли я сделать это в iOS 17, и если да, то как? И во-вторых, мне интересно узнать, в чем разница между этими тремя подходами к аргументам Init?
mutableRating: Binding<Int?>
mutableRating: Binding<Int>?
mutableRating: (Binding<Int>)?
Обновлено: Разъяснение ошибок
Когда я использую
mutableRating: Binding<Int?>
&
self._mutableRating = mutableRating
Я получаю Missing argument for parameter 'mutableRating' in call в предварительном просмотре non mutating. Я предполагаю, что этот параметр на самом деле не является необязательным, что имеет смысл, учитывая упомянутые различия.
Если я изменю строку аргумента на
mutableRating: Binding<Int>? чтобы сделать сам параметр необязательным, я получаю Cannot assign value of type 'Binding<Int>' to type 'Binding<Int?>' on the initialization line. One of the fix options offered suggests that this might work, self._mutableRating = mutableRating ?? nilbut that producesНевозможно присвоить значение типа «Привязка?» набрать 'Binding<Int?>'`, что возвращает нас к изменению аргумента.
@joakim-danielson У меня было ощущение, что 3 — это просто более подробная версия 2. Так каковы варианты использования первых двух? И как мне инициализировать второй?





Вот мое упрощенное решение совместного использования необязательной привязки к необязательному типу и необязательному свойству.
struct TestView: View {
var mutableRating: Binding<Int?>?
let currentRating: Int?
init(mutableRating: Binding<Int?>?) {
self.mutableRating = mutableRating
currentRating = nil
}
init(rating: Int?) {
self.mutableRating = Optional<Binding<Int?>>.none
currentRating = rating
}
var body: some View {
if let mutableRating {
TextField("Rating", value: mutableRating, format: .number.precision(.fractionLength(0)))
.padding()
} else if let currentRating {
Text(currentRating.formatted())
}
}
}
#Preview {
return TestView(mutableRating: .constant(42))
}
#Preview ("non mutating") {
struct PreviewWrapper: View {
var body: some View {
VStack {
TestView(rating: 3)
}
.padding()
}
}
return PreviewWrapper()
}
Протестировано на iOS 17.4 и macOS 14.
Но работает ли это без передачи mutableRating? Кажется, именно здесь я упираюсь в стену. Я могу заставить его работать, когда ДЕЙСТВИТЕЛЬНО передаю этот аргумент, но в варианте без мутации я получаю ошибку, из-за которой кажется, что этот параметр на самом деле не является необязательным, как мне нужно.
Кажется, я не понимаю ваш второй пример предварительного просмотра. Почему вы хотите передать постоянное значение свойству привязки?
В том то и дело, а я нет. Поэтому мне нужен один параметр, используемый в первом предварительном просмотре, который принимает привязку, а затем другой параметр во втором предварительном просмотре, который принимает простое целое число. И в результате оба должны быть необязательными.
Хорошо, я пропустил, что вы использовали другое свойство для постоянного значения.
С моей точки зрения, я считаю, что вы ищете:
public init(
...
mutableRating: Binding<Int?> = .constant(nil),
...
) { }
В приведенном выше коде действительны оба предварительного просмотра mutating и non mutating.
Ага! Мне нужно будет немного почитать, чтобы понять, что именно делает этот .constant(nil), но я думаю, что это сработает. Теперь я могу заставить все это работать, а затем опубликовать отдельно, чтобы посмотреть, скажет ли кто-нибудь: «Этот код пахнет всякими видами, даже если он работает» :)
Собственно, с @Binding это правильно делать, особенно когда вы макетируете данные в режиме предварительного просмотра. Вам стоит взглянуть на туториалы по SwiftUI.
Я думаю, что .optional предназначен только для предварительного просмотра.
Раньше я использовал его в качестве заполнителя пользовательского интерфейса. У меня было представление с двумя состояниями, первое состояние предназначено только для демонстрации, в котором .constant используется для представления своего рода демонстрационных данных. Другое состояние для реальных данных, полученных из BE.
Первый — это привязка к необязательному типу, второй — необязательная привязка к типу, а третий — такой же, как второй. Поэтому, если вы используете их в качестве параметров функции, вы можете передать nil двум последним, но первый не может быть нулевым, хотя его связанное значение может быть нулевым.