如何在 SwiftUI 中删除“表单”的顶部空间?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中删除“表单”的顶部空间?【英文标题】:How to remove top space of `Form` in SwiftUI? 【发布时间】:2019-11-03 14:43:47 【问题描述】:

如何在NavigationView 中对齐Form。我有以下内容,当我从正文中删除 NaviagationView 时,Form 是顶部对齐的。使用NavigationView,我在两者之间获得了间距(添加了红色框以显示空间)。我可以在表单上使用.padding(.top, -20),但是虽然这可行,但它会稍微倾斜。

NavigationView 
    Form 
        VStack 
            HStack 
                Text("Name:").underline().font(.headline)
                TextField("Name", text: $routine.name)
                
            
            roundPicker()
            TimeSelectionView(stateName: "A", stateDuration: "0:30", stateBackground: "#df405a")
            TimeSelectionView(stateName: "B", stateDuration: "1:30", stateBackground: "#4ea1d3")
            TimeSelectionView(stateName: "C", stateDuration: "3:00", stateBackground: "#4f953b")
        
    
    .navigationBarTitle("Create", displayMode: .inline)
    .navigationBarItems(trailing:
        Button(action: 
            //Save Routine
            self.routine.rounds = self.roundsArray[self.rounds]
            
            print("Workout Name: \(self.routine.name)")
            print("Workout Rounds: \(self.routine.rounds)")
            , label: 
                Text("Save")
            
        )
    )
 

【问题讨论】:

.listStyle(GroupedListStyle()) 应用于List 视图时也会出现差距,并且接受的答案也适用于这种情况。 【参考方案1】:

SwiftUI Form 实际上是一个分组样式 UITableView 在底层,这是默认的 tableHeaderView。所以你可以像这样删除它:

ios 13

struct ContentView: View 
    
    init()  // this can be done in `onAppear` modifier if you need to restore the appereance later on `onDisappear`
        UITableView.appearance().tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: Double.leastNonzeroMagnitude))
    
    
    var body: some View 
        ,,,
    

iOS 14

Apple 正在限制 appearance hack,设置 tableHeaderView 的框架就是其中之一,因此我们需要通过添加以下步骤来进一步挖掘:

1。使用约束代替frame

init() 
    let view = UIView()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.heightAnchor.constraint(equalToConstant: 0).isActive = true
    UITableView.appearance().tableHeaderView = view

2。强制重新加载表:

已添加约束,但需要重新加载。 SwiftUI 不允许您手动重新加载列表。所以我们需要添加一个虚拟视图和一个虚拟state 来欺骗它:

@State var loaded = false // need for stay update
,,,

    List 

        if loaded 
            Text("Actual content of the list")

         else 
            Text("Dummy content. Not important")
                .onAppear 
                    loaded = true // need for instatnt force update 
                
        

    

注1:

尽量不要对任何数字进行硬编码(例如插入 -35!)。数字在不同的设备、平台和状态等方面有所不同。

注2:

.zero 框架不工作。如果你在 iOS 13 上使用 frameUIKit,你应该至少通过一个最小高度。

注3:

所有方法都是hacks,Apple 正试图限制对UITableView 等底层类型的访问。因此,请及时了解最新情况并尝试帮助社区。​​p>

注4:

通过点赞和评论为社区做出贡献。所以人们会更有动力去未知的地方挖掘,给我们带来很酷的东西。

注5:

由于我们使用外观代理,任何更改都将应用于应用程序中的所有TableViews。您可以存储原始Appearance 的状态 -> 应用新样式onAppear 并在需要时恢复原始onDisaper

【讨论】:

谢谢!就是这样! 有什么办法不一定在整个应用程序范围内执行此操作,而仅针对表单? 是的。在 Appear() 上做 这也适用于 iPad 上带有 SidebarStyle() 的列表。甚至在 Xcode12 中为 List 工作,没有尝试过 Form。 @MojtabaHosseini 很久以前,我知道,但你的建议仍然使它成为全球性的,只是从这段代码第一次执行 onAppear 开始。【参考方案2】:

在 Xcode 12 中设置表头视图不再适合我。相反,设置负顶部内容插入似乎可以达到同样的效果。

UITableView.appearance().contentInset.top = -35

【讨论】:

这是 Xcode 12 的正确答案。谢谢!!【参考方案3】:

如果您使用Introspect,请将其添加到您的 NavigationView

.introspectTableView 
    $0.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: Double.leastNonzeroMagnitude))

【讨论】:

【参考方案4】:

Cleaner 在表单部分添加导航栏标题,然后设置隐藏

Form 
// add end of form section
.navigationBarHidden(true).navigationBarTitle("Title") // Form

【讨论】:

这会删除导航栏,而不是第一个表单元素上方的空间。

以上是关于如何在 SwiftUI 中删除“表单”的顶部空间?的主要内容,如果未能解决你的问题,请参考以下文章

如何在swiftUI中删除顶部安全区域

SwiftUI 无法删除选取器上方的空间 - 表单版本

如何从 Mac OS 中的 SwiftUI 列表中删除底部/顶部项目填充

顶部细节视图中不会消失的额外空间 (SwiftUI)

如何在swiftui中删除绿色多余的空间

如何使用 SwiftUI 消除嵌套 NavigationView 中的空间