#ios #swift #swiftui
Вопрос:
Я хочу показать представление во время выполнения задач, как еще я мог бы вызвать SwiftView для отображения без использования условных обозначений, основанных на bool состояния? В принципе, я хочу избежать того, чтобы это было жестко закодировано ниже для каждого файла, для которого потребуется представление загрузки…
struct ContentView: View {
@State var doIWantThisViewToShow: Bool = false
var body: some View {
VStack {
Button("Show/Hide MyView") {
doIWantThisViewToShow.toggle()
}
if doIWantThisViewToShow {
MyView()
.padding()
}
}
}
}
Комментарии:
1. Вы имеете в виду, что у вас будет список файлов (например, в
ForEach
), и вы не хотите писать по одному@State
для каждого из них? Вы можете абстрагировать его в собственный компонент, так что вы напишете его только@State
один раз, но будете повторно использовать компонент (View
) снова и снова.2. @jnpdx В принципе, лучшим примером является вход в приложение в Firebase. Я должен показать представление загрузки, но я не хочу писать его как условие для каждой «страницы» в моем приложении, привязанной к bool. Потому что, если я сделаю это таким образом, мне придется писать на каждой странице. если doIWantThisViewToShow { MyView() .заполнение() }
3. Почему это должно быть на каждой странице? Напишите это как условие для самого верхнего родительского представления, и оно будет применяться ко всему, что находится под ним.
4. @jnpdx спасибо за ясность, но каково самое верхнее родительское представление или как это будет выглядеть в коде?
5. Это выглядит точно так же, как у вас сейчас, при условии, что вы делаете все остальное дочерним представлением (существует внутри)
MyView
.
Ответ №1:
Вы можете изучить несколько стратегий, позволяющих уменьшить количество дубликатов кода.
- Пользовательское значение среды, чтобы избежать передачи @Binding
- Многократно используемые эффекты
- Может быть, протокол, если ваше состояние сложное (возможно, нет)
Изменение иерархии представлений
Пользователь EnvironmentValue
передает состояние дочерним представлениям. Это избавит вас от передачи @Binding через представления, которые могут не использовать значение.
Имейте в виду, что это односторонняя трансляция сверху вниз. В отличие от @Binding, дети не могут изменять родительское состояние. (Но они могут изменить знания своих собственных детей об этом состоянии.)
Установить в родительском
@State var isHovered = false
var parent: some View {
///
.environment(.parentIsHovered, isHovered)
}
Наблюдайте за ребенком
@Environment(.parentIsHovered) var parentIsHovered
var child: some View {
///
.grayscale(parentIsHovered ? 0 : 0.9)
.animation(.easeInOut, value: parentIsHovered)
}
Определять
private struct ParentIsHoveredKey: EnvironmentKey {
static let defaultValue: Bool = false
}
extension EnvironmentValues {
var parentIsHovered: Bool {
get { return self[ParentIsHoveredKey] }
set { self[ParentIsHoveredKey] = newValue }
}
}
Многократно используемые эффекты
Если вы выделяете определенные виды серым цветом или отображаете индикатор загрузки, вы можете использовать модификатор вида, который принимает привязку и условно отображает наложение, фон или эффекты.
Приведенный ниже пример демонстрирует это, связывая .animation
API с accessibilityReduceMotion
.
// view
.animate(.easeOut(duration: .fast), value: isLoading)
extension View {
func animate<E: Equatable>(_ animation: Animation?, value: E) -> some View {
self.modifier(AccessibleAnimationModifier(animation, for: value))
}
}
struct AccessibleAnimationModifier<E: Equatable>: ViewModifier {
@Environment(.accessibilityReduceMotion) var reduceMotion
init(_ animation: Animation? = .default, for value: E) {
self.animation = animation
self.value = value
}
var animation: Animation?
var value: E
func body(content: Content) -> some View {
content
.animation(reduceMotion ? .none : animation, value: value)
}
}
Реагирование на состояние загрузки
Если вы не обрабатываете состояние загрузки с помощью какого-либо наблюдаемого класса, вам необходимо сохранить это состояние в своем представлении с помощью @State.
Возможно, протокол с реализацией по умолчанию в расширении помогает уменьшить дублирование кода при вычислении сложного состояния загрузки между представлениями.
Псевдокод ниже определяет источник перетаскивания протокола с функциями, возвращающими NSItemProvider. Расширение предоставляет реализации по умолчанию, которые может вызывать представление или виртуальная машина.
protocol DragSource {
func makeDraggableThing1(/// content logic objects) -> NSItemProvider
}
extension DragSource {
func makeDraggableThing1(///) -> NSItemProvider {
/// Default work I only want to edit once in the app
}
}