How to clear background for TextField inside list in macOS

Issue #986 When using TextField in SwiftUI List on Mac, it has unwanted background color when focused. We can turn it off using introspection or a custom TextField wrapper TextField("Search", text: $searchText) .introspect(.textField, on: .macOS(.v14, .v15)) { $0.drawsBackground = true $0.backgroundColor = .clear }

November 5, 2024 · 1 min · 44 words · Khoa

How to use NSDragOperation

Issue #981 NSDragOperation represent which operations the dragging source can perform on dragging items. There are several types of drag operations, and each one has a different purpose and visual cue. Copy Operation .copy What It Does: The item you’re dragging will be copied. This means the original stays in place, and a duplicate is created in the new location. When to Use: Use this when you want to create a copy of a file or item, without removing it from the original spot....

September 23, 2024 · 3 min · 609 words · Khoa

How to make NSCollectionView with diffable data source and SwiftUI

Issue #980 NSCollectionView, available since macOS 10.5+, is a good choice to present a list of content. Let’s make a SwiftUI wrapper for NSCollectionView with diffable data source and compositional layout Use NSViewControllerRepresentable First, let’s create a SwiftUI view that will represent the macOS view controller. We’ll use the NSViewControllerRepresentable protocol to bridge SwiftUI and AppKit. import SwiftUI import AppKit struct CollectionView: NSViewControllerRepresentable { func makeNSViewController(context: Context) -> CollectionViewController { return CollectionViewController() } func updateNSViewController(_ nsViewController: CollectionViewController, context: Context) { nsViewController....

August 15, 2024 · 3 min · 627 words · Khoa

How to check NSTextField is first responder

Issue #961 NSTextField uses NSFieldEditor under the hood, you can check currentEditor if it is the firstResponder extension NSTextField { var isFirstResponder: Bool { currentEditor() == window?.firstResponder } }

January 7, 2024 · 1 min · 29 words · Khoa

How to make attributed TextView for macOS and iOS with SwiftUI

Issue #956 macOS import Foundation import SwiftUI import AppKit struct AttributedTextView: NSViewRepresentable { @Binding var attributedText: NSAttributedString var isEditable: Bool = true final class Coordinator: NSObject { let parent: AttributedTextView init( parent: AttributedTextView ) { self.parent = parent super.init() } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeNSView(context: Context) -> NSScrollView { let view = NSTextView.scrollableTextView() if let textView = view.documentView as? NSTextView { textView.font = NSFont.preferredFont(forTextStyle: ....

December 7, 2023 · 2 min · 257 words · Khoa

How to drag multiple files in SwiftUI on Mac

Issue #951 Create a custom NSView that handles mouseDragged to beginDraggingSession struct DraggingSourceViewWrapper: NSViewRepresentable { let fileUrls: [URL] let onEnd: () -> Void func makeNSView(context: Context) -> DraggingSourceView { let view = DraggingSourceView(fileUrls: fileUrls) view.onEnd = onEnd return view } func updateNSView(_ view: DraggingSourceView, context: Context) { view.onEnd = onEnd } } final class DraggingSourceView: NSView { let fileUrls: [URL] var onEnd: (() -> Void)? init(fileUrls: [URL]) { self.fileUrls = fileUrls super....

November 13, 2023 · 2 min · 237 words · Khoa

How to clear TextEditor background in SwiftUI

Issue #920 For iOS 16 and macOS 13.0 TextEditor(text: $text) .scrollContentBackground(.hidden) For below, use [SwiftUI-Introspect](https://github.com/siteline/SwiftUI-Introspect) TextEditor(text: $text) .instrospectTextView { $0.drawsBackground = false }

June 19, 2023 · 1 min · 23 words · Khoa

How to create Quick look thumbnail for files

Issue #913 Use QuickLookThumbnailing framework import AppKit import QuickLookThumbnailing actor QuicklookService { static let shared = QuicklookService() private let generator = QLThumbnailGenerator.shared func image( fileUrl: URL, size: CGSize ) async -> NSImage { let scale = NSScreen.main?.backingScaleFactor ?? 2 let request = QLThumbnailGenerator.Request( fileAt: fileUrl, size: size, scale: scale, representationTypes: .thumbnail ) do { let representation = try await generator.generateBestRepresentation(for: request) return representation.nsImage } catch { return NSWorkspace.shared.icon(forFile: fileUrl.path) } } } Read more Creating Quick Look Thumbnails to Preview Files in Your App

May 13, 2023 · 1 min · 84 words · Khoa

How to show animated gif NSImage on Mac

Issue #903 let image = NSImage(contentsOf: url) let imageView = NSImageView(image: image) image.animates = true

September 25, 2022 · 1 min · 15 words · Khoa

How to find previous frontmost application in macOS

Issue #900 Listen to didActivateApplicationNotification and check that it is not our app NSWorkspace.shared.notificationCenter .publisher(for: NSWorkspace.didActivateApplicationNotification) .sink(receiveValue: { [weak self] note in guard let app = note.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication, app.bundleIdentifier != Bundle.main.bundleIdentifier else { return } self?.frontMostApp = app }) .store(in: &bag)

August 2, 2022 · 1 min · 42 words · Khoa

How to convert NSImage to PNG Data

Issue #885 Create NSBitmapImageRep with preferred size and draw NSImage onto that. Need to construct NSBitmapImageRep specifically instead of using convenient initializers like NSBitmapImageRep(data:), NSBitmapImageRep(cgImage:) to avoid device dependant resolution issue. extension NSImage { func pngData( size: CGSize, imageInterpolation: NSImageInterpolation = .high ) -> Data? { guard let bitmap = NSBitmapImageRep( bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bitmapFormat: [], bytesPerRow: 0, bitsPerPixel: 0 ) else { return nil } bitmap....

June 6, 2022 · 1 min · 114 words · Khoa

How to select in List in SwiftUI

Issue #881 Specify optional value for List(selection:). This keeps selection on macOS, but not on iPad. On iPad each row in the List needs to be NavigationLink, no need for .tag. The selection is not updated, need to manually update with onTapGesture For List selection to work, make sure selection binding type matches. Preferablly using ID than Self Need to specify id in ForEach for List to infer tag. Otherwise, need to specify tag for cell struct Sidebaer: View { class ViewModel: ObservableObject { @Published var group: BookGroup?...

May 27, 2022 · 1 min · 170 words · Khoa

How to create document based macOS app

Issue #875 Read newDocument This method calls openUntitledDocumentAndDisplay(_:). Read openUntitledDocumentAndDisplay The default implementation of this method calls defaultType to determine the type of new document to create, calls makeUntitledDocument(ofType:) to create it, then calls addDocument(_:) to record its opening. Read defaultType The default implementation of this method returns the first Editor type declared by the CFBundleDocumentTypes array in the application’s Info.plist, or returns nil if no Editor type is declared. You can override it to customize the type of document that is created when, for instance, the user chooses New in the File menu....

March 19, 2022 · 1 min · 97 words · Khoa

How to deinit NSWindow

Issue #848 Hold a weak reference to NSWindow, and let system window server manages its lifetime weak var window = NSWindow() window.isReleasedWhenClosed = true

September 9, 2021 · 1 min · 24 words · Khoa

How to convert NSEvent locationInWindow to window coordinate

Issue #822 Get active screen with mouse func activeScreen() -> NSScreen? { let mouseLocation = NSEvent.mouseLocation let screens = NSScreen.screens let screenWithMouse = (screens.first { NSMouseInRect(mouseLocation, $0.frame, false) }) return screenWithMouse } Reposition our NSWIndow if window.frame != screen.frame { window.setFrameOrigin(screen.frame.origin) window.setContentSize(screen.frame.size) } Flip y as AppKit has coordinate origin starting from bottom left of the screen, while our SwiftUI starts from top left var point = window.convertPoint(fromScreen: event.locationInWindow) point.y = window....

July 13, 2021 · 1 min · 76 words · Khoa

How to show modal window in AppKit

Issue #806 Use runModal https://developer.apple.com/documentation/appkit/nsapplication/1428590-runmodalsession Blocks main queue A loop that uses this method is similar in some ways to a modal event loop run with runModal(for:), except with this method your code can do some additional work between method invocations. When you invoke this method, events for the NSWindow object of this session are dispatched as normal. This method returns when there are no more events. You must invoke this method frequently enough in your loop that the window remains responsive to events....

June 24, 2021 · 1 min · 180 words · Khoa

How to resize NSImage with padding

Issue #795 extension NSImage { func resize(width: CGFloat, height: CGFloat, padding: CGFloat) -> NSImage { let img = NSImage(size: CGSize(width: width, height: height)) img.lockFocus() let ctx = NSGraphicsContext.current ctx?.imageInterpolation = .high self.draw( in: NSMakeRect(0, 0, width, height), from: NSMakeRect(0, -padding, size.width, size.height - padding), operation: .copy, fraction: 1 ) img.unlockFocus() return img } } So we can use like button.image = NSImage(named: NSImage.Name("pastePal"))?.resize(width: 22, height: 22, padding: -4)

April 15, 2021 · 1 min · 68 words · Khoa

How to convert from paid to freemium in SwiftUI with RevenueCat

Issue #794 I’ve been distributing my apps PastePal and Push Hero as a paid upfront apps on Appstore. I’ve quickly come to realize the importance of trials since many have requested a tryout before purchasing. Manual sending out trials comes with its own problem. I need to notarize and package the app as a dmg file, and not to even mention implement my own trial mechanism to check and notify of expired builds....

April 11, 2021 · 5 min · 1023 words · Khoa

How to manage WindowGroup in SwiftUI for macOS

Issue #789 Using WindowGroup New in SwiftUI 2.0 for iOS 14 and macOS 11.0 is WindwGroup which is used in App protocol. WindowGroup is ideal for document based applications where you can open multiple windows for different content or files. For example if you’re developing a text editor or drawing apps, you can show multiple windows for different text file or drawing. All is handled automatically for you if you use WindowGroup...

March 7, 2021 · 6 min · 1085 words · Khoa

How to use Core Data

Issue #785 Core Data Responding to changes in a managed object context Calling mergeChanges on a managed object context will automatically refresh any managed objects that have changed. This ensures that your context always contains all the latest information. Note that you don’t have to call mergeChanges on a viewContext when you set its automaticallyMergesChangesFromParent property to true. In that case, Core Data will handle the merge on your behalf....

February 26, 2021 · 6 min · 1109 words · Khoa