How to check dark mode with color scheme in SwiftUI

Issue #692 Use colorScheme environment, for now it has 2 cases dark and light struct MainView: View { @Environment(\.colorScheme) var colorScheme var body: some View { Text(colorScheme == .dark ? "Dark Mode" : "Light Mode") } }

November 10, 2020 · 1 min · 37 words · Khoa

How to make full size content view in SwiftUI for macOS

Issue #689 func applicationDidFinishLaunching(_ aNotification: Notification) { // extend to title bar let contentView = ContentView() // .padding(.top, 24) // can padding to give some space .edgesIgnoringSafeArea(.top) // specify fullSizeContentView window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), styleMask: [.titled, .closable, .miniaturizable, .texturedBackground, .resizable, .fullSizeContentView], backing: .buffered, defer: false ) window.center() window.setFrameAutosaveName("My App") // window.title = ... // no title // window.toolbar = NSToolbar() // use toolbar if wanted....

November 3, 2020 · 1 min · 135 words · Khoa

How to override styles in SwiftUI

Issue #688 In the app I’m working on Elegant Converter, I usually like preset theme with a custom background color and a matching foreground color. Thanks to SwiftUI style cascading, I can just declare in root MainView and it will be inherited down the view hierachy. struct MainView: View { var body: some View { HSplitView { ListView() RightView() } .foregroundColor(R.color.text) .background(R.color.background) } } This works great regardless of system light or dark mode, but in light mode it does not look good, as my designed theme is similar to dark mode....

October 31, 2020 · 2 min · 215 words · Khoa

How to use CoreData safely

Issue #686 I now use Core Data more often now. Here is how I usually use it, for example in Push Hero From iOS 10 and macOS 10.12, NSPersistentContainer that simplifies Core Data setup quite a lot. I usually use 1 NSPersistentContainer and its viewContext together with newBackgroundContext attached to that NSPersistentContainer In Core Data, each context has a queue, except for viewContext using the DispatchQueue.main, and each NSManagedObject retrieved from 1 context is supposed to use within that context queue only, except for objectId property....

October 25, 2020 · 2 min · 299 words · Khoa

How to pass ObservedObject as parameter in SwiftUI

Issue #685 Since we have custom init in ChildView to manually set a State, we need to pass ObservedObject. In the ParentView, use underscore _ to access property wrapper type. struct ChildView: View { @ObservedObject var store: Store @State private var selectedTask: AnyTask init(store: ObservedObject<Store>) { _selectedTask = State(initialValue: tasks.first!) _store = store } } struct ParentView: View { @ObservedObject var store: Store var body: some View { ChildView(store: _store) }

October 24, 2020 · 1 min · 71 words · Khoa

How to do equal width in SwiftUI

Issue #684 In SwiftUI, specifying maxWidth as .infinity means taking the whole available width of the container. If many children ask for max width, then they will be divided equally. This is similar to weight in LinearLayout in Android or css flex-grow property. The same applies in vertical direct also. struct ContentView: View { var body: some View { HStack(spacing: 0) { VStack { Spacer() } .frame(maxWidth: .infinity) .background(Color.red) VStack { Spacer() } ....

October 23, 2020 · 1 min · 135 words · Khoa

How to style multiline Text in SwiftUI for macOS

Issue #681 Only need to specify fixedSize on text to preserve ideal height. The maximum number of lines is 1 if the value is less than 1. If the value is nil, the text uses as many lines as required. The default is nil. Text(longText) .lineLimit(nil) // No need .fixedSize(horizontal: false, vertical: true) If the Text is inside a row in a List, fixedSize causes the row to be in middle of the List, workaround is to use ScrollView and vertical StackView....

October 7, 2020 · 1 min · 98 words · Khoa

How to clear List background color in SwiftUI for macOS

Issue #680 For List in SwiftUI for macOS, it has default background color because of the enclosing NSScrollView via NSTableView that List uses under the hood. Using listRowBackground also gives no effect The solution is to use a library like SwiftUI-Introspect import Introspect extension List { func removeBackground() -> some View { return introspectTableView { tableView in tableView.backgroundColor = .clear tableView.enclosingScrollView!.drawsBackground = false } } } then List { ForEach(items) { item in // view here } } ....

October 4, 2020 · 1 min · 204 words · Khoa

How to avoid reduced opacity when hiding view with animation in SwiftUI

Issue #679 While redesigning UI for my app Push Hero, I ended up with an accordion style to toggle section. It worked great so far, but after 1 collapsing, all image and text views have reduced opacity. This does not happen for other elements like dropdown button or text. extension View { func sectionBackground(_ title: String, _ shows: Binding<Bool>) -> some View { VStack(alignment: .leading) { HStack { Text(title.uppercased()) Spacer() if shows !...

October 1, 2020 · 1 min · 141 words · Khoa

How to dynamically add items to VStack from list in SwiftUI

Issue #678 Use enumerated to get index so we can assign to item in list. Here is how I show list of device tokens in my app Push Hero private var textViews: some View { let withIndex = input.deviceTokens.enumerated().map({ $0 }) let binding: (Int, Input.DeviceToken) -> Binding<String> = { index, token in Binding<String>( get: { token.token }, set: { self.input.deviceTokens[index].token = $0 } ) } return VStack { ForEach(withIndex, id: \....

October 1, 2020 · 1 min · 82 words · Khoa

How to unwrap Binding with Optional in SwiftUI

Issue #677 The quick way to add new properties without breaking current saved Codable is to declare them as optional. For example if you use EasyStash library to save and load Codable models. import SwiftUI struct Input: Codable { var bundleId: String = "" // New props var notificationId: String? This new property when using dollar syntax $input.notificationId turn into Binding with optional Binding<Strting?> which is incompatible in SwiftUI when we use Binding....

September 29, 2020 · 1 min · 136 words · Khoa

How to make custom toggle in SwiftUI

Issue #676 I’ve used the default SwiftUI to achieve the 2 tab views in SwiftUI. It adds a default box around the content and also opinionated paddings. For now on light mode on macOS, the unselected tab has wrong colors. The way to solve this is to come up with a custom toggle, that we can style and align the way we want. Here is how I did for my app Push Hero...

September 29, 2020 · 1 min · 195 words · Khoa

How to use Binding in function in Swift

Issue #675 Use wrappedValue to get the underlying value that Binding contains extension View { func addOverlay(shows: Binding<Bool>) -> some View { HStack { self Spacer() } .overlay( HStack { Spacer() SmallButton( imageName: "downArrow", tooltip: shows.wrappedValue ? "Collapse" : "Expand", action: { shows.wrappedValue.toggle() } ) .rotationEffect(.radians(shows.wrappedValue ? .pi : 0)) } ) } }

September 25, 2020 · 1 min · 54 words · Khoa

How to use HSplitView to define 3 panes view in SwiftUI for macOS

Issue #674 Specify minWidth to ensure miminum width, and use .layoutPriority(1) for the most important pane. import SwiftUI struct MainView: View { @EnvironmentObject var store: Store var body: some View { HSplitView { LeftPane() .padding() .frame(minWidth: 200, maxWidth: 500) MiddlePane(store: store) .padding() .frame(minWidth: 500) .layoutPriority(1) RightPane() .padding() .frame(minWidth: 300) } .background(R.color.background) } }

September 23, 2020 · 1 min · 53 words · Khoa

How to make switch statement in SwiftUI

Issue #656 Lately I’ve been challenging myself to declare switch statement in SwiftUI, or in a more generalized way, execute any anonymous function that can return a View Use Switch and Case views Note that this approach does not work yet, as TupeView should support variadic number of contents, and also T.RawValue needs to conform to Equatable in order to check the cases. Also in Switch statement, Content can’t be inferred...

May 22, 2020 · 2 min · 280 words · Khoa

How to conditionally apply modifier in SwiftUI

Issue #633 Use autoclosure and AnyView @available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) public extension View { func applyIf<T: View>(_ condition: @autoclosure () -> Bool, apply: (Self) -> T) -> AnyView { if condition() { return apply(self).erase() } else { return self.erase() } } } Button(action: onSearch) { Image("search") .resizable() .styleButton() .overlay(ToolTip("Search")) } .buttonStyle(BorderlessButtonStyle()) .applyIf(showsSearch, apply: { $0.foregroundColor(Color.orange) })

March 30, 2020 · 1 min · 61 words · Khoa

How to toggle with animation in SwiftUI

Issue #632 Use Group private func makeHeader() -> some View { Group { if showsSearch { SearchView( onSearch: onSearch ) .transition(.move(edge: .leading)) } else { InputView( onAdd: onAdd ) .transition(.move(edge: .leading)) } } } withAnimation { self.showsSearch.toggle() }

March 30, 2020 · 1 min · 38 words · Khoa

How to show context popover from SwiftUI for macOS

Issue #630 For SwiftUI app using NSPopover, to show context popover menu, we can ask for windows array, get the _NSPopoverWindow and calculate the position. Note that origin of macOS screen is bottom left (lldb) po NSApp.windows ▿ 2 elements - 0 : <NSStatusBarWindow: 0x101a02700> - 1 : <_NSPopoverWindow: 0x101c01060> let handler = MenuHandler() handler.add(title: "About", action: onAbout) handler.add(title: "Quit", action: onQuit) guard let window = NSApp.windows.last else { return } let position = CGPoint( x: window....

March 22, 2020 · 1 min · 90 words · Khoa

How to make segmented control in SwiftUI for macOS

Issue #629 Use Picker with SegmentedPickerStyle. Picker(selection: $preferenceManager.preference.display, label: EmptyView()) { Image("grid") .resizable() .padding() .tag(0) Image("list") .resizable() .tag(1) }.pickerStyle(SegmentedPickerStyle()) .frame(width: 50) .padding(.leading, 16) .padding(.trailing, 24) Alternatively, we can make custom NSSegmentedControl import AppKit import SwiftUI struct MySegmentControl: NSViewRepresentable { func makeCoordinator() -> MySegmentControl.Coordinator { Coordinator(parent: self) } func makeNSView(context: NSViewRepresentableContext<MySegmentControl>) -> NSSegmentedControl { let control = NSSegmentedControl( images: [ NSImage(named: NSImage.Name("grid"))!, NSImage(named: NSImage.Name("list"))! ], trackingMode: .selectOne, target: context.coordinator, action: #selector(Coordinator.onChange(_:)) ) return control } func updateNSView(_ nsView: NSSegmentedControl, context: NSViewRepresentableContext<MySegmentControl>) { } class Coordinator { let parent: MySegmentControl init(parent: MySegmentControl) { self....

March 22, 2020 · 1 min · 104 words · Khoa

How to trigger onAppear in SwiftUI for macOS

Issue #626 SwiftUI does not trigger onAppear and onDisappear like we expect. We can use NSView to trigger import SwiftUI struct AppearAware: NSViewRepresentable { var onAppear: () -> Void func makeNSView(context: NSViewRepresentableContext<AppearAware>) -> AwareView { let view = AwareView() view.onAppear = onAppear return view } func updateNSView(_ nsView: AwareView, context: NSViewRepresentableContext<AppearAware>) { } } final class AwareView: NSView { private var trigged: Bool = false var onAppear: () -> Void = {} override func viewDidMoveToSuperview() { super....

March 18, 2020 · 1 min · 118 words · Khoa