How to check app going to background in SwiftUI

Issue #746 From iOS 13, the default is to support multiple scene, so the the old UIApplicationDelegate lifecycle does not work. Double check your Info.plist for UIApplicationSceneManifest key <key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> <true/> </dict> One way to be notified about application life cycle is to use UIApplicationDelegateAdaptor and via NotificationCenter import SwiftUI import UIKit import FontAwesomeSwiftUI final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FontAwesome....

January 7, 2021 · 1 min · 110 words · Khoa

How to use selection in List in SwiftUI

Issue #745 I used to use selection with Binding where wrappedValue is optional, together with tag in SwiftUI for macOS, and it shows current selection @Binding var selection: Tag? = .all List(section: $selection) { Text("All") .tag(Tag.all) } From the API, looks like Binding<Set> is for multiple selection, and Binding<Optional> is for single selection Looking at List signature, I see that selection uses wrappedValue as Set for Binding<Set<SelectionValue>>? init<Data, ID, RowContent>(Data, id: KeyPath<Data....

January 6, 2021 · 1 min · 129 words · Khoa

How to make tiled image in SwiftUI

Issue #737 Use resizingMode of .tile with a tile image from https://www.transparenttextures.com/ Image("transparentTile") .resizable(capInsets: .init(), resizingMode: .tile) .scaleEffect(2) .aspectRatio(contentMode: .fit) .frame(maxWidth: .infinity, maxHeight: .infinity) .clipped()

January 2, 2021 · 1 min · 25 words · Khoa

How to use WebView in SwiftUI

Issue #736 struct MyWebView: NSViewRepresentable { let url: URL @Binding var isLoading: Bool func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeNSView(context: Context) -> WKWebView { let view = WKWebView() view.navigationDelegate = context.coordinator view.load(URLRequest(url: url)) return view } func updateNSView(_ nsView: WKWebView, context: Context) { } class Coordinator: NSObject, WKNavigationDelegate { let parent: MyWebView init(parent: MyWebView) { self.parent = parent } func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) { parent....

January 2, 2021 · 1 min · 88 words · Khoa

How to use GeometryReader in SwiftUI

Issue #735 From my previous post How to use flexible frame in SwiftUI we know that certain views have different frame behaviors. 2 of them are .overlay and GeometryReader that takes up whole size proposed by parent. By default GeometryReader takes up whole width and height of parent, and align its content as .topLeading struct ContentView_Previews: PreviewProvider { static var previews: some View { VStack { Rectangle() .fill(Color.gray) .overlay( GeometryReader { geo in Text("\(Int(geo....

January 1, 2021 · 1 min · 192 words · Khoa

How to use flexible frame in SwiftUI

Issue #734 In SwiftUI there are fixed frame and flexible frame modifiers. Fixed frame Positions this view within an invisible frame with the specified size. Use this method to specify a fixed size for a view’s width, height, or both. If you only specify one of the dimensions, the resulting view assumes this view’s sizing behavior in the other dimension. VStack { Ellipse() .fill(Color.purple) .frame(width: 200, height: 100) Ellipse() .fill(Color.blue) ....

January 1, 2021 · 7 min · 1320 words · Khoa

How to make view appear with delay in SwiftUI

Issue #731 Sometimes we don’t want to show progress view right away HUDProgressView() .transition( AnyTransition.asymmetric( insertion: AnyTransition.opacity.animation(Animation.default.delay(1)), removal: AnyTransition.opacity) )

December 31, 2020 · 1 min · 20 words · Khoa

How to make attributed string Text in SwiftUI for macOS

Issue #730 Use NSTextField with maximumNumberOfLines import AppKit import SwiftUI struct AttributedText: NSViewRepresentable { let attributedString: NSAttributedString init(_ attributedString: NSAttributedString) { self.attributedString = attributedString } func makeNSView(context: Context) -> NSTextField { let textField = NSTextField() textField.lineBreakMode = .byClipping textField.maximumNumberOfLines = 0 textField.isBordered = false return textField } func updateNSView(_ nsView: NSTextField, context: Context) { nsView.attributedStringValue = attributedString } } TextField has problem with wrapping, we can use TextView struct AttributedTextView: NSViewRepresentable { typealias NSViewType = NSScrollView let attributedText: NSAttributedString?...

December 31, 2020 · 1 min · 154 words · Khoa

How to make visual effect blur in SwiftUI for macOS

Issue #724 We can use .blur modifier, but with VisualEffectView gives us more options for material and blending mode. public struct VisualEffectView: NSViewRepresentable { let material: NSVisualEffectView.Material let blendingMode: NSVisualEffectView.BlendingMode public init( material: NSVisualEffectView.Material = .contentBackground, blendingMode: NSVisualEffectView.BlendingMode = .withinWindow ) { self.material = material self.blendingMode = blendingMode } public func makeNSView(context: Context) -> NSVisualEffectView { let visualEffectView = NSVisualEffectView() visualEffectView.material = material visualEffectView.blendingMode = blendingMode visualEffectView.state = NSVisualEffectView.State.active return visualEffectView } public func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context) { visualEffectView....

December 26, 2020 · 1 min · 88 words · Khoa

How to make simple HUD in SwiftUI

Issue #723 Use @ViewBuilder to build dynamic content for our HUD. For blur effect, here I use NSVisualEffectView, but we can use .blur modifier also struct HUD<Content>: View where Content: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content } var body: some View { content() .frame(width: 80, height: 80) .background( VisualEffectView(material: .hudWindow) .clipShape(RoundedRectangle(cornerRadius: 12)) .shadow(color: Color.black.opacity(0.22), radius: 12, x: 0, y: 5) ) } } Then we can make some wrappers for information and progress HUD...

December 26, 2020 · 1 min · 132 words · Khoa

How to instrument SwiftUI app

Issue #722 With Xcode 12, we can fire up Instrument to profile our app. Select SwiftUI template There are many profiles in that template, I find SwiftUI and Time Profile very useful. Here’s the profile I run for my app PastePal SwiftUI View Body This shows how many instance of View with body invocation are there, both for SwiftUI views and our app views Taking a look at SwiftUI profile, it shows that ClipboardCell is taking most of the time, here over 7 seconds...

December 25, 2020 · 2 min · 294 words · Khoa

How to show image and text in menu item in SwiftUI for macOS

Issue #719 From SwiftUI 2 for macOS 11.0, we have access to Menu for creating menu and submenu. Usually we use Button for interactive menu items and Text for disabled menu items. The easy way to customize menu with image is to call Menu with content and label. Pay attention to how we use Button and Label inside Content to create interactive menu items Menu( content: { ForEach(collections) { collection in Button(action: {) { Label(collection....

December 23, 2020 · 1 min · 187 words · Khoa

How to make sharing menu in SwiftUI for macOS

Issue #718 Use NSSharingService.sharingServices(forItems:) with an array of one empty string gives a list of sharing items. There we show image and title of each menu item. We should cache sharing items as that can cause performance issue import SwiftUI import AppKit import EasySwiftUI extension NSSharingService { private static let items = NSSharingService.sharingServices(forItems: [""]) static func submenu(text: String) -> some View { return Menu( content: { ForEach(items, id: \.title) { item in Button(action: { item....

December 23, 2020 · 1 min · 112 words · Khoa

How to make stepper with plus and minus buttons in SwiftUI for macOS

Issue #717 Try to use predefined system colors in Human Interface Guidelines for macOS Here we use this color unemphasizedSelectedTextBackgroundColor for button background HStack(spacing: 1) { makeUnderListButton(action: {}, icon: .plus) makeUnderListButton(action: {}, icon: .minus) } .background(Color(NSColor.unemphasizedSelectedTextBackgroundColor)) .cornerRadius(4) func makeUnderListButton(action: @escaping () -> Void, icon: AwesomeIcon) -> some View { Button(action: action) { Text(icon.rawValue) .font(.awesome(style: .solid, size: 14)) } .buttonStyle(HighlightButtonStyle(h: 8, v: 6, cornerRadius: 4)) } Another thing is List, where we have selected and alternative background colors....

December 21, 2020 · 1 min · 129 words · Khoa

How to fix Picker not showing selection in SwiftUI

Issue #716 I have an enum that conforms to CaseIterable that I want to show in Picker enum Position: String, Codable, CaseIterable, Identifiable { var id: String { rawValue } case left case right case bottom case top } Picker(selection: $preference.position, label: Text("Position")) { ForEach(Preference.Position.allCases) { position in Text(position.rawValue) } } It compiles and runs just fine, but Picker does not show current selection regardless of any Picker style I choose....

December 20, 2020 · 2 min · 259 words · Khoa

How to do didSet for State and Binding in SwiftUI

Issue #714 Below is an example of a parent ContentView with State and a child Sidebar with a Binding. The didSet is only called for the property that is changed. When we click Button in ContentView, that changes State property, so only the didSet in ContentView is called When we click Button in Sidebar, that changes Binding property, so only the didSet in Sidebar is called enum Tag: String { case all case settings } struct ContentView: View { @State private var tag: Tag = ....

December 16, 2020 · 2 min · 325 words · Khoa

How to programatically select row in List in SwiftUI

Issue #711 List has a selection parameter where we can pass selection binding. As we can see here selection is of type optional Binding<Set<SelectionValue>>? where SelectionValue is any thing conforming to Hasable @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public struct List<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View { @available(watchOS, unavailable) public init(selection: Binding<Set<SelectionValue>>?, @ViewBuilder content: () -> Content) So we can programatically control selection by tagging row with our own Tag...

December 13, 2020 · 1 min · 113 words · Khoa

How to show sidebar in SwiftUI for macOS

Issue #710 Starting from macOS 11, we can use List with SidebarListStyle inside NavigationView to declare master detail view. The SidebarListStyle makes list translucent. It automatically handles selection and marks selected row in list with accent color. struct MainView: some View { var body: some View { NavigationView { sidebar ContentView() } } private var sidebar: some View { List { Group { Text("Categories") .foregroundColor(.gray) ForEach(categories) { category in NavigationLink(destination: ContentView(category: category)) { Label(category....

December 13, 2020 · 1 min · 199 words · Khoa

How to disable NSTextView in SwiftUI

Issue #702 The trick is to use an overlay MessageTextView(text: $input.message) .overlay(obscure) var obscure: AnyView { if store.pricingPlan.isPro { return EmptyView().erase() } else { return Color.black.opacity(0.01).erase() } }

November 27, 2020 · 1 min · 28 words · Khoa

How to use nested ObservableObject in SwiftUI

Issue #694 I usually structure my app to have 1 main ObservableObject called Store with multiple properties in it. final class Store: ObservableObject { @Published var pricingPlan: PricingPlan() @Published var preferences: Preferences() } struct Preferences { var opensAtLogin: Bool = true } final class PricingPlan: ObservableObject { @Published var isPro: Bool = true } SwiftUI for now does not work with nested ObservableObject, so if I pass Store to PricingView, changes in PricingPlan does not trigger view update in PricingView....

November 14, 2020 · 1 min · 212 words · Khoa