HowTo —— SwiftUI2.0 使用 ToolBar 替代 navigationbarItems

发表于

为您每周带来有关 Swift 和 SwiftUI 的精选资讯!

SwiftUI 2.0 为了实现更好的多平台支持同时需要兼顾 1.0 版本代码兼容性,提供了一些与已有控件功能上类似但名称和用法全新的控件。比如 ToolBar, navigationTitle 等。Toolbar 可以实现 navigationbarItems 的全部功能,并新增了在多平台下的适配。采用了全新的语法,代码更易阅读。

在当前的 Xcode Version 12.0 beta 2 (12 A 6163 b) 版本下,ToolBar 在 macOS 下仍然有非常多的问题。

基本用法

Swift
struct ToolBarTest: View {
    var body: some View {
      NavigationView{
        Text("ToolBar 演示")
            .toolbar{
                ToolbarItem(placement:.automatic){
                    HStack(spacing:20){
                        Button(action:{print("wave")}){
                            Image(systemName: "waveform.path.badge.plus")
                                .foregroundColor(.purple)
                                .scaleEffect(1.5, anchor: .center)
                        }
                        
                    }
                }
                //placement 设置放置位置,ToolBarItem 中的 View 解析不会完全和预期一致,不知道是特别限制还是 bug. 比如说无法显示多彩符号,无法使用 Spacer 等。
                ToolbarItem(placement: .bottomBar){
                    HStack(spacing:100){
                        Button(action:{print("lt")}){
                            Image(systemName: "lt.rectangle.roundedtop.fill")
                                .foregroundColor(.purple)
                                .scaleEffect(1.5, anchor: .center)
                        }
                        
                        Button(action:{print("rt")}){
                            Image(systemName: "rt.rectangle.roundedtop.fill")
                                .foregroundColor(.purple)
                                .scaleEffect(1.5, anchor: .center)
                        }
                    }
                }
            }
        }
    }
}

![截屏 2020-07-10 上午 9.01.52]( https://cdn.fatbobman.com/howto-swiftui-toolbar-toolbar1.png width=300)

多平台适配

为了能够更好的适配多平台,placment 提供了 automatic 这样的多平台自适应选项。placement 有些值全平台可用,有些只支持部分平台,还有一部分的可在多平台运行不过只能在部分平台正确显示。

Swift
import SwiftUI

struct ToolBarTest: View {
    @State var placementSelection:Placement = .automatic
    @State var placement:ToolbarItemPlacement = .automatic
    @State var show = true
    var body: some View {
        NavigationView{
            VStack{
                Picker("placement:",selection:$placementSelection){
                    ForEach(Placement.allCases,id:\.self){ placement in
                        Text(placement.rawValue)
                            .tag(placement)
                    }
                }
                .labelsHidden()
                .padding(.all, 10)
                .onChange(of: placementSelection) { value in
                    switch value{
                    case .automatic:
                        placement = .automatic
                    case .principal:
                        placement = .principal //iOS 不显示
                    case .navigation:
                        placement = .navigation
                    case .primaryAction:
                        placement = .primaryAction
                    case .status:
                        placement = .status //iOS 不显示
                    case .confirmationAction:
                        placement = .confirmationAction //iOS 不显示
                    case .cancellationAction:
                        placement = .cancellationAction //iOS 不显示
                    case .destructiveAction:
                        placement = .destructiveAction //iOS 不显示
                    #if os(iOS)
                    case .bottomBar:
                        placement = .bottomBar
                    //不知道为什么有 bug, 设置后不显示
                    //ToolbarItem(placement:.bottomBar) 可以显示
                    case .navigationBarLeading:
                        placement = .navigationBarLeading
                    case .navigationBarTrailing:
                        placement = .navigationBarTrailing
                    #endif
                    }
                }
                //在 macOS 下如果需要显式设置是否显示 ToolBar, 需要设置 id,iOS 下可以不用设置
                //当前在 macOS 下,如果不显式关闭可能导致不同 View 的 ToolBar 混合到了一起,或者重复出现。不知道是否是 bug 还是设计逻辑
                .toolbar(id:"ToolBar") {
                    ToolbarItem(id:"1",placement:placement,showsByDefault:show) {
                        Button("确定"){
                            
                        }
                    }
                }
                .navigationTitle("Toolbar 演示")
                
                #if os(macOS)
                Toggle("显示 ToolBar",isOn:$show)
                Spacer()
                #endif
            } .frame(maxWidth:.infinity,maxHeight: .infinity)
        }
        
    }
}

enum Placement:String,CaseIterable{
    case automatic,principal,navigation
    case primaryAction,status,confirmationAction
    case cancellationAction,destructiveAction
    #if os(iOS)
    case navigationBarLeading,navigationBarTrailing,bottomBar
    #endif
}

macOS 下不同 placement 的演示

遗憾

macOS 目前 bug 较多,ToolBarItem 对于 View 的解析还不完整,ToolBarContentBuilder 不支持逻辑判断。

我非常期待听到您的想法! 请在下方留下您的评论 , 分享您的观点和见解。或者加入我们的 Discord 讨论群 ,与更多的朋友一起交流。

Fatbobman(东坡肘子)

热爱生活,乐于分享。专注 Swift、SwiftUI、Core Data 及 Swift Data 技术分享。欢迎关注我的社交媒体,获取最新动态。

你可以通过以下方式支持我