[英]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.您可以探索一些减少重复代码的策略。
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 的认识。)
@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 }
}
}
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)
}
}
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.