简体   繁体   English

在 SwiftUI 中显示和隐藏视图

[英]Showing and hiding views in SwiftUI

I want to show a view while tasks complete, how else could I call a SwiftView to show without using conditionals based on a State bool?我想在任务完成时显示一个视图,如果不使用基于 State bool 的条件,我还能如何调用 SwiftView 来显示? Basically I want to avoid having this hardcoded below for every file that is gonna need the loading view...基本上我想避免在下面为每个需要加载视图的文件进行硬编码......

struct ContentView: View {
    @State var doIWantThisViewToShow: Bool = false
    
    var body: some View {
        VStack {
            Button("Show/Hide MyView") {
                doIWantThisViewToShow.toggle()
            }
            if doIWantThisViewToShow {
                MyView()
                    .padding()
            }
        }
    }
}

You can explore a few strategies to reduce duplicate code.您可以探索一些减少重复代码的策略。

  1. Custom Environment value to avoid passing @Binding自定义环境值以避免传递 @Binding
  2. Reusable effects可重复使用的效果
  3. Maybe a protocol if your state is complex (probably not)如果您的 state 很复杂(可能不是),则可能是一个协议

Mutating a view hierarchy改变视图层次结构

A custom EnvironmentValue broadcasts a state down to child views.自定义EnvironmentValue将 state 向下广播到子视图。 This will save you from passing @Binding through views that may not consume the value.这将使您免于通过可能不使用该值的视图传递@Binding。

Keep in mind this is a one-way top-down broadcast.请记住,这是一种单向自上而下的广播。 Unlike @Binding, children can't mutate parent state.与@Binding 不同,孩子不能改变父母 state。 (But they can mutate their own children's knowledge of said state.) (但他们可以改变自己孩子对 state 的认识。)

Set in Parent在父级中设置

@State var isHovered = false

var parent: some View {
///
  .environment(\.parentIsHovered, isHovered)
}

Observe in Child观察孩子

@Environment(\.parentIsHovered) var parentIsHovered

var child: some View {
///
   .grayscale(parentIsHovered ? 0 : 0.9)
   .animation(.easeInOut, value: parentIsHovered)
}

Define定义

private struct ParentIsHoveredKey: EnvironmentKey {
    static let defaultValue: Bool = false
}


extension EnvironmentValues {
    
    var parentIsHovered: Bool {
        get { return self[ParentIsHoveredKey] }
        set { self[ParentIsHoveredKey] = newValue }
    }
}

Reusable effects可重复使用的效果

If you gray out certain views or display a loading indicator, you can use a ViewModifier that accepts a Binding and conditionally displays an overlay, background or effects.如果您将某些视图变灰或显示加载指示器,则可以使用接受 Binding 并有条件地显示覆盖、背景或效果的 ViewModifier。

The example below demonstrates that by linking the .animation API to accessibilityReduceMotion .下面的示例通过将.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)
    }
}

Reacting to loading state响应加载 state

Unless you handle loading state through some observed class, you need to store that state in your View using @State.除非您通过一些观察到的 class 处理加载 state,否则您需要使用 @State 将 state 存储在您的视图中。

Maybe a protocol with a default implementation in an extension helps reduce duplicate code in computing a complex loading state between Views.也许在扩展中具有默认实现的协议有助于在计算视图之间的复杂加载 state 时减少重复代码。

The pseudocode below defines a protocol DragSource with functions returning an NSItemProvider.下面的伪代码定义了一个协议 DragSource,其函数返回一个 NSItemProvider。 The extension provides default implementations that a View or VM can call.该扩展提供了 View 或 VM 可以调用的默认实现。

protocol DragSource {
    
    func makeDraggableThing1(/// content + logic objects) -> NSItemProvider

}

extension DragSource {
    
    func makeDraggableThing1(///) -> NSItemProvider {
        /// Default work I only want to edit once in the app
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM