代码编织梦想

Posted 1 year ago by Peter Steinberger

Pretty much all Mac apps have a semi-hidden Debug menu that can be triggered via a user defaults entry or via settings. Naturally I wanted to add the same in my latest project. I’m building a new “universal” app (meaning iOS and macOS), supporting only the latest OSes, so I can using the new SwiftUI app lifecycle.

SwiftUI is really a lot of fun to work with. Sure, there are bugs, warts and parts that simply aren’t finished yet, especially on the Mac, but overall what Apple built here is really great, and it’s so much faster to build apps with it. SwiftUI makes the hard things simple, and sometimes it makes the simple things hard.

Menus in SwiftUI App Lifecycle

Let’s look at a typical menu definition in the new Big Sur/iOS 14 SwiftUI App Lifecycle. The syntax is straightforward and fits right into the concepts of SwiftUI. Bingings work as well and menus change on-demand as state changes.

@main
struct SampleApp: App {
    var body: some Scene {
        WindowGroup {
            MainAppView()
        }
        .commands {
            CommandGroup(replacing: CommandGroupPlacement.newItem) {
                Button("Import Archive") {
                    activeSheet = .importer
                }
                .keyboardShortcut(KeyEquivalent("i"), modifiers: .command)
            }
    }
}

There’s a superb guide over at TrozWare about SwifUI Mac Menus that explains everything in detail - including a way how to move the menu logic into a separate file. Highly recommended. Let’s move on to the interesting bits.

Showing Menus Conditionally

Within CommandMenu it’s easy to use if/else to conditionally show menu entries. SwiftUI uses @ViewBuilder as resultbuilder and conditionals are correctly implemented.

CommandMenu("Animals") {
    if user.likesCats {
        Button("Show Cat Picture") { }        
    } else {
        Button("Show Dog Picture") { }        
    }

However if we try the same at the top level, we get an error: "Closure containing control flow statement cannot be used with result builder 'CommandsBuilder'"gs. The SwiftUI-team didn’t implement any branching logic into the @CommandsBuilder.

After a discussion on Twitter, there really doesn’t seem a SwiftUI-way to trigger the visibility of top-level menus. @LeoNatan suggested to drop back into AppKit, and that’s what I ended up doing:

static func triggerDebugMenuVisibilityHack() {
    if let mainMenu = NSApp.mainMenu {
        DispatchQueue.main.async {
            if !Features.shared.isDebugModeEnabled,
               let debugMenu = mainMenu.items.first(where: { $0.title == "Debug" }) {
                mainMenu.removeItem(debugMenu)
            }
        }
    }
}

Make sure to trigger this both on app start and whenever the debug value changes:

.onAppear {
    DebugMenuCommands.triggerDebugMenuVisibilityHack()
}
.onChange(of: features.isDebugModeEnabled) { _ in
    DebugMenuCommands.triggerDebugMenuVisibilityHack()
}

And that’s it. Toggling the menu works just as expected. In our update method we have to skip a runloop so the SwiftUI glue has time to set up the menu, however this gets called so early in the app startup lifecycle that it’s not visible. So while not the most elegant solution, this works perfectly fine.

Conclusion

This is a good reminder that even when writing a “Pure SwiftUI” application, the underlying frameworks are there and can help you whenever you run into a limitation of SwiftUI. Since this feels like an omission, I’ve opened a radar (FB9074334) for the SwiftUI team.

使用xmake构建stm32程序_anobodykey的博客-爱代码爱编程

主机环境:Windows 7 SP1 编译器版本:gcc-arm-none-eabi-7-2017-q4-major-win32 目标板:STM32F103C8T6单板 STM32库版本:STM32Cube_FW_F1_V1.6.0 XMAKE版本:2.1.9 之前一段时间一直在思索跨平台开发的问题,以前开发STM32用的是MDK开发环境,但该软件又只能在

android studio 快捷用法_weixin_33725272的博客-爱代码爱编程

AndroidStudio已经用了两年左右了,对快捷键的使用一直如同段誉的六脉神剑一般,偶尔会biu不出来,从来没有静下心来耐心的看完Tips,为了避免这种尴尬,决定把Tips完整的练习一遍并记录在案。 AndroidStudio版本:2.2 计算机操作系统: Windows 7 提示 ##如果关闭了提示对话框,可在 H

css-移动端 base模板_weixin_33750452的博客-爱代码爱编程

2019独角兽企业重金招聘Python工程师标准>>> @charset "utf-8"; /* CSS Document author:dreambreeze*/ body {     font-family: "Helvetica Neue", sans-serif;     font-size: 14px

Gitlab之docker容器介绍参考文档-爱代码爱编程

Help GitLab Container Registry (FREE) Introduced in GitLab 8.8. Docker Registry manifest v1 support was added in GitLab 8.9 to support Docker versions earlier than 1.10. Starting

前端-CSS,语法、元素、属性、动画、计算方法布局及简单实战项目-爱代码爱编程

拿出来大家共勉,不足之处请指正。 很久之前的学习笔记了,一直存放在本地中 文章目录 CSS语法(cascanding style sheet层叠样式表)引入样式表外部样式内部样式内联样式选择器选择器的权重单位像素百分比emremRGBA十六进制伪类伪元素标签属性常用标签文本属性字体属性字体样式大小font-sizefont-family服务器字体@f