развертывание необязательно в View SwiftUI - PullRequest
0 голосов
/ 14 октября 2019

Я пытаюсь развернуть свое необязательное свойство, но получаю это сообщение об ошибке: Закрытие, содержащее оператор потока управления, не может использоваться с конструктором функций 'ViewBuilder'

Я не вижу, что не так с моим кодом

Код:

HStack {
            if let height = profile.height {
                TagBox(field: "height", value: String(height))
            }
            TagBox(field: "nationality", value: profile.nationality)
            Spacer()
        }.padding(.horizontal)

Ответы [ 3 ]

1 голос
/ 14 октября 2019

В этом контексте есть два способа работы с дополнительными компонентами:

Первый, если вы вообще не хотите, чтобы это представление отображалось, если profile.height равен nil:

profile.height.map({ TagBox(field: "height", value: String($0))})

Второй, если вы хотите, чтобы это представление отображалось, но вместо него было указано значение по умолчанию:

TagBox(field: "height", value: String(profile.height ?? 0))
0 голосов
/ 14 ноября 2019

Так что, если принудительное развертывание заставляет вас чувствовать себя неловко, вы можете использовать следующий пользовательский вид, который я составил:

struct OptionalView<Value, Content>: View where Content: View {
    var content: (Value) -> Content
    var value: Value

    init?(_ value: Value?, @ViewBuilder content: @escaping (Value) -> Content) {
        guard let value = value else {
            return nil
        }
        self.value = value

        self.content = content
    }

    var body: some View {
        content(value)
    }
}

И использовать его так:

OptionalView(profile.height) { height in
    TagBox(field: "height", value: String(height))
}

Я написалпост об этом и создание цепочки необязательных просмотров здесь

0 голосов
/ 14 октября 2019

Вы можете иметь операторы if в конструкторе представлений Group. Я сделал пример, чтобы проиллюстрировать:

var label1 = "label 1"
@State var label2: String?
var label3: String? = "label 3"

var body: some View {
    VStack {
        Text(label1)
        Group {
            if label2 != nil {
                Text(label2!)
            }
            if label3 != nil {
                Text(label3!)
            }
        }
        Button(action: {
            self.label2 = "Button pressed!"
        }) {
            Text("Press me!")
        }
    }
}

Конечно, в этом примере вы могли бы просто сделать Text(label2 ?? ""), но был бы пробел, где Text до тех пор, пока label2 не будет иметь значениеа также, в более сложных ситуациях, это обеспечивает большую гибкость. Если вы запустите этот код, вы увидите «Метка 1» непосредственно над «Меткой 3», а если вы нажмете кнопку «Кнопка нажата!»появится между "Label 1" и "Label 3".

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

В предоставленном вами коде вы можете изменить его на:

HStack {
    Group {
        if profile.height != nil {
            TagBox(field: "height", value: String(profile.height!))
        }
    }
    TagBox(field: "nationality", value: profile.nationality)
    Spacer()
}.padding(.horizontal)

Хорошая особенность этого решения заключается в том, что в сценарии вы можете делать более сложные вещи, когда значение равно нулю (или нет), и даже предоставлять представление по умолчанию, если значение равно нулю (в моем примереэто будет эквивалентно добавлению else для оператора if с Button, Text и т. д. внутри тела else).

Один недостатокчто вам нужно явно развернуть опциональные объекты, что не должно быть проблемой, потому что оператор if позаботится о том, чтобы убедиться, что он не равен nil, но я все же нахожу, что необязательное связывание - это, как правило, более чистый путь для развертывания опциональных файлов. 1025 * Редактировать :

Если вы действительно не хотите явно развертывать дополнительные опции, вы можете использовать ViewBuilder s:

var label1 = "label 1"
@State var label2: String?
var label3: String? = "label 3"
var body: some View {
    VStack {
        Text(label1)
        Group {
            self.conditionalText(self.label2)
            if label3 != nil {
                Text(label3!)
            }
        }
        Button(action: {
            self.label2 = "Button pressed!"
        }) {
            Text("Press me!")
        }
    }
}
func conditionalText(_ text: String?) -> some View {
    if let text = text {
        return ViewBuilder.buildIf(Text(text))
    } else {
        print("Text is nil")
    }
    let view: Text? = nil
    return ViewBuilder.buildIf(view)
}

Этот метод также показывает, как вы можете иметьисполняемый код внутри Group, если он находится внутри функции, которая возвращает представление.

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