99

我正在尝试有条件DatePicker地在 SwiftUI 中隐藏 a 。但是,我对不匹配的类型有任何问题:

var datePicker = DatePicker($datePickerDate)
if self.showDatePicker {
    datePicker = datePicker.hidden()
}

在这种情况下,datePicker是一个DatePicker<EmptyView>类型但是datePicker.hidden()是一个_ModifiedContent<DatePicker<EmptyView>, _HiddenModifier>。所以我不能分配datePicker.hidden()datePicker. 我已经尝试过这种方法的变体,但似乎找不到可行的方法。有任何想法吗?

更新

您可以使用它的属性打开_ModifiedContent类型以获取基础类型。content但是,这并不能解决根本问题。该content属性似乎只是原始的、未修改的日期选择器。

4

9 回答 9

134

隐藏视图的最简单和最常见的方法如下:

struct ContentView: View {
    @State private var showText = true

    var body: some View {
        VStack {
            Button("Toggle text") {
                showText.toggle()
            }

            if showText {
                Text("Hello World!")
            }
        }
    }
}

这会在equals时从层次结构中删除Text视图。如果您希望选择保留空间或希望将其作为修饰符,请参见下文。showTextfalse


我创建了一个扩展,所以你可以使用修饰符,像这样隐藏视图:

Text("Hello World!")
    .isHidden(true)

或完全删除:

Text("Label")
    .isHidden(true, remove: true)

如果你想使用 Swift Packages,下面的扩展也可以在 GitHub 上找到:GeorgeElsham/HidingViews


下面是创建View修饰符的代码:

我建议您在自己的文件中使用此代码(记住import SwiftUI):

extension View {
    /// Hide or show the view based on a boolean value.
    ///
    /// Example for visibility:
    ///
    ///     Text("Label")
    ///         .isHidden(true)
    ///
    /// Example for complete removal:
    ///
    ///     Text("Label")
    ///         .isHidden(true, remove: true)
    ///
    /// - Parameters:
    ///   - hidden: Set to `false` to show the view. Set to `true` to hide the view.
    ///   - remove: Boolean value indicating whether or not to remove the view.
    @ViewBuilder func isHidden(_ hidden: Bool, remove: Bool = false) -> some View {
        if hidden {
            if !remove {
                self.hidden()
            }
        } else {
            self
        }
    }
}
于 2019-12-07T17:09:06.897 回答
113

✅ 正确和最简单的方法:

您可以改为设置 alpha,这也将保留视图的布局空间,并且不会像其他答案一样强制您添加虚拟视图:

.opacity(isHidden ? 0 : 1)

演示

演示


更清洁的方式!- 扩展原始hidden修饰符:

此外,您可以实现一个自定义函数来获取可见性状态作为参数:

extension View {
    func hidden(_ shouldHide: Bool) -> some View {
        opacity(shouldHide ? 0 : 1)
    }
}

现在只需将 传递bool给修饰符:

DatePicker($datePickerDate)
    .hidden(showDatePicker)

请注意,hidden修改器的原始行为不同,这两种方法都保留了隐藏视图的框架。


⛔️不要使用不良做法!!!

所有其他答案(包括@Jake 接受的答案)使用分支而不是导致性能下降的依赖代码。

分支示例:

分支

✅ 依赖代码示例:

依赖代码示例

为不同的状态返回逻辑SAME视图会导致 SwiftUI 渲染引擎重新渲染并再次初始化视图并导致性能下降!(在此 WWDC 会议上查看更多信息)

于 2019-08-08T20:56:28.303 回答
60

我发现我能够以这种方式隐藏或显示日期选择器,而不是动态设置变量并在我的视图中使用它:

struct ContentView : View {
    @State var showDatePicker = true
    @State var datePickerDate: Date = Date()

    var body: some View {
        VStack {
            if self.showDatePicker {
                DatePicker($datePickerDate)
            } else {
                DatePicker($datePickerDate).hidden()
            }
        }
    }
}

或者,可选地,不包括日期选择器而不是隐藏它:

struct ContentView : View {
    @State var showDatePicker = true
    @State var datePickerDate: Date = Date()

    var body: some View {
        VStack {
            if self.showDatePicker {
                DatePicker($datePickerDate)
            }
        }
    }
}
于 2019-06-07T08:42:32.243 回答
21

这是在 SwiftUI 中显示/隐藏视图的简单方法。

  1. 添加@State变量:

    @State var showLogo = false
    
  2. 添加条件如下:

    VStack {
                if showLogo == true {
                Image(systemName: "house.fill")
                    .resizable()
                    .frame(width: 100, height: 100, alignment: .center)
                    .foregroundColor(Color("LightGreyFont"))
                    .padding(.bottom, 20)
                }
                Text("Real State App")
                    .font(Font.custom("Montserrat-Regular", size: 30))
            }.padding(.vertical, 25)
    
  3. 将 @State 变量的状态更改为显示/隐藏视图,如下所示:

    Button(action: {
                    withAnimation{
                        self.showLogo.toggle()
                    }
    
                }, label: {
                    Text("Login").font(.system(size: 20, weight: .medium, design: .default))
                        .frame(minWidth: 0, maxWidth: .infinity, maxHeight: 50)
                        .foregroundColor(Color("BlackFont"))
                        .cornerRadius(10)
    
                })
    

在此处输入图像描述

于 2020-09-09T06:03:50.103 回答
8

编辑 2021 年 11 月 4 日

我现在更喜欢另一种方法,而不是原始答案中的方法(如下):

有两种可能的解决方案,具体取决于您是要保留原始空间还是让其他视图占用隐藏的空间。

保留空间

DatePicker("Choose date", selection: $datePickerDate)
    .opacity(showDatePicker ? 1 : 0)

即使我们在这里只调整不透明度,触摸DatePicker隐藏时应该在的空间也不会打开日历。

不要保留空间

if showDatePicker {
    DatePicker("Choose date", selection: $datePickerDate)
}

原始答案

对于将来需要它的人,我创建了一个ViewModifier接受一个Boolas 参数的方法,因此您可以绑定一个布尔值,通过设置showDatePicker: Bool变量以声明方式显示和隐藏视图。

所有代码片段都需要 import SwiftUI.

ViewModifier: _

struct Show: ViewModifier {
    let isVisible: Bool

    @ViewBuilder
    func body(content: Content) -> some View {
        if isVisible {
            content
        } else {
            content.hidden()
        }
    }
}

功能:

extension View {
    func show(isVisible: Bool) -> some View {
        ModifiedContent(content: self, modifier: Show(isVisible: isVisible))
    }
}

你可以像这样使用它:

var datePicker = DatePicker($datePickerDate)
                     .show(isVisible: showDatePicker)
于 2020-08-20T09:33:38.550 回答
6

按住 Command 键单击有问题的视图,然后在 Beta 5 中选择 Make Conditional 选项。我在我的一个视图 (LiftsCollectionView) 上执行此操作,它生成了以下内容:

    if suggestedLayout.size.height > 150 {
      LiftsCollectionView()
    } else {
      EmptyView()
    }
于 2019-08-13T02:43:26.513 回答
2

您还可以opacity在 any 上使用修饰符View

ActivityIndicator(tint: .black)
   .opacity(self.isLoading ? 1.0 : 0.0)
于 2020-03-18T18:09:59.397 回答
0

即使没有占位符视图或调用隐藏,以下内容也适用(iOS13.1 和 Swift 5)

struct Foo: View {
    @State var condition: Bool

    var body: some View {
        if self.condition {
            Text("Hello")
        }
    }
}

如果不查看实现,很难确切地知道@ViewBuilder,但是在评估条件时,我们似乎得到了EmptyView默认情况下是否失败。

所以这相当于这里的一些答案,但更简单。

于 2021-04-22T12:57:34.793 回答
0

以下自定义修饰符与 .hidden() 一样,通过隐藏视图和禁用与它的交互来实现。

ViewModifier 和视图扩展功能 -

import SwiftUI

fileprivate struct HiddenIfModifier: ViewModifier {
  var isHidden: Bool
  
  init(condition: Bool) {
    self.isHidden = condition
  }
  
  func body(content: Content) -> some View {
    content
      // Conditionally changing the parameters of modifiers
      // is more efficient than conditionally applying a modifier
      // (as in Cristina's ViewModifier implementation).
      .opacity(isHidden ? 0 : 1)
      .disabled(isHidden)
  }
}

extension View {
    /// Hides a view conditionally.
    /// - Parameters:
    ///   - condition: Decides if `View` is hidden.
    /// - Returns: The `View`, hidden if `condition` is `true`.
    func hidden(if condition: Bool) -> some View {
        modifier(HiddenIfModifier(condition: condition))
    }
}

利用 -

DatePicker($datePickerDate)
  .hidden(if: !self.showDatePicker)

注意 - 有条件地应用修饰符是低效的,因为 swift 将未修改和已修改的视图视为不同的类型。这会导致视图(及其状态)在每次条件发生变化时被破坏和重建。对于 List 等数据量大的视图,这可能会成为一个问题。有条件地更改修饰符的参数不会导致此问题。

于 2022-01-10T01:16:25.933 回答