How to customize NSTextView in AppKit

Issue #320 Scrollable Putting an NSTextView Object in an NSScrollView Use xib then load Embed image or NSTextAttachmentCellProtocol Select TextView Select Rich Text and Graphics Select Size Inspector -> Resizable and tick both Horizontally and Vertically Customize scrollView.drawsBackground = false textView.drawsBackground = false textView.string = "What's on your mind?" textView.delegate = self textView.selectedTextAttributes = [ NSAttributedString.Key.backgroundColor: NSColor(hex: "414858"), NSAttributedString.Key.foregroundColor: NSColor(hex: "ACB2BE") ] extension MainView: NSTextViewDelegate { func textViewDidChangeSelection(_ notification: Notification) { // Change text color again after image dragging } }

June 22, 2019 · 1 min · 81 words · Khoa

How to use custom font in AppKit

Issue #319 Add fonts to targets Declare in Info.plist https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/GeneralPurposeKeys.html#//apple_ref/doc/uid/TP40009253-SW8 ATSApplicationFontsPath (String - macOS) identifies the location of a font file or directory of fonts in the bundle’s Resources directory. If present, macOS activates the fonts at the specified path for use by the bundled app. The fonts are activated only for the bundled app and not for the system as a whole. The path itself should be specified as a relative directory of the bundle’s Resources directory....

June 22, 2019 · 1 min · 111 words · Khoa

How to make custom controller for View in iOS

Issue #318 I do UI in code, and usually separate between View and ViewController. class ProfileView: UIView {} class ProfileViewController: UIViewController { override func loadView() { self.view = ProfileView() } } But in places where using UIViewController and manage their view controller containment hierarchy is not desired, then we can roll out a normal object to act as the controller. class ProfileController { let profileView: ProfileView init(profileView: ProfileView) { self.profileView = profileView } func update(profile: Profile) { profileView....

June 19, 2019 · 1 min · 103 words · Khoa

How to make UIPanGestureRecognizer work with horizontal swipe in UICollectionView

Issue #315 extension PanCollectionViewController: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { let velocity = panGR.velocity(in: panGR.view) return abs(velocity.y) > abs(velocity.x) } }

June 18, 2019 · 1 min · 24 words · Khoa

How to avoid crash when closing NSWindow for agent macOS app

Issue #312 class ClosableWindow: NSWindow { override func close() { self.orderOut(NSApp) } } let window = ClosableWindow( contentRect: rect, styleMask: [.titled, .closable], backing: .buffered, defer: false } window.makeKeyAndOrderFront(NSApp) The reason is that window is released upon closed if it is not owned by NSWindowController, or we can use releasedWhenClosed The value of this property is YES if the window is automatically released after being closed; NO if it’s simply removed from the screen....

June 16, 2019 · 1 min · 116 words · Khoa

How to get cell at center during scroll in UICollectionView

Issue #311 See Omnia https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/UICollectionView.swift#L30 extension HorizontalUsersViewController: UIScrollViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let point = view.convert(collectionView.center, to: collectionView) guard let indexPath = collectionView.indexPathForItem(at: point), indexPath.item < users.count else { return } let user = users[indexPath.item] delegate?.didScrollTo(user) } }

June 14, 2019 · 1 min · 40 words · Khoa

How to downsample image in iOS

Issue #310 https://www.swiftjectivec.com/optimizing-images/ https://nshipster.com/image-resizing/

June 14, 2019 · 1 min · 4 words · Khoa

How to show location in Apple Maps and Google Maps app in iOS

Issue #309 Apple Maps let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: nil) let mapItem = MKMapItem(placemark: placemark) mapItem.name = shop.name mapItem.openInMaps(launchOptions: [:]) Google Maps https://developers.google.com/maps/documentation/urls/ios-urlscheme Use q to show pin Since iOS 9, we need to declare LSApplicationQueriesSchemes <key>LSApplicationQueriesSchemes</key> <array> <string>comgooglemaps</string> </array> var string = "comgooglemaps://" string += "?q=Food" string += "&center=\(coordinate.latitude),\(coordinate.longitude)" string += "&zoom=15" let googleUrl = URL(string: string)! if UIApplication.shared.canOpenURL(URL(string: "comgooglemaps://")!) { UIApplication.shared.open(googleUrl) }

June 13, 2019 · 1 min · 65 words · Khoa

How to make convenient touch handler for UIButton in iOS

Issue #308 If you don’t want to use https://github.com/onmyway133/EasyClosure yet, it’s easy to roll out a closure based UIButton. The cool thing about closure is it captures variables final class ClosureButton: UIButton { var didTouch: (() -> Void)? override init(frame: CGRect) { super.init(frame: frame) addTarget(self, action: #selector(buttonTouched(_:)), for: .touchUpInside) } required init?(coder aDecoder: NSCoder) { fatalError() } @objc private func buttonTouched(_: UIButton) { didTouch?() } } Then in cellForItem func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell: UserCell = collectionView....

June 13, 2019 · 1 min · 157 words · Khoa

How to format distance in iOS

Issue #307 import MapKit let formatter = MKDistanceFormatter() formatter.unitStyle = .abbreviated formatter.units = .metric distanceLabel.text = formatter.string(fromDistance: distance) // 700m, 1.7km

June 13, 2019 · 1 min · 21 words · Khoa

How to mock grpc model in Swift

Issue #306 let json: [String: Any] = [ "id": "123", "name": "Thor", "isInMarvel": true ] let data = try JSONSerialization.data(withJSONObject: json, options: []) let string = String(data: data, encoding: .utf8)! return try Hero(jsonString: string) If we use withValue from How to simplify struct mutating in Swift then we can mock easily extension Hero { static func mock() -> Hero { return withValue(Hero()) { $0.id = "123" $0.name = "Thor" $0.isInMarvel = true } } }

June 13, 2019 · 1 min · 75 words · Khoa

Favorite WWDC 2019 sessions

Issue #305 This year I’m lucky enough to get the ticket to WWDC and I couldn’t be more satisfied. 5 conference days full of awesomeness, talks, labs and networking, all make WWDC special and memorial conference for every attendee. As predicted by many, Marzipan (now officially called Project Catalyst) a technology that could allow iOS apps to be ported to macOS, would be the main topic for this year. But WWDC went more spectacular than that, with dark mode on iOS, independent watchOS apps, and SwiftUI being the star of the show....

June 12, 2019 · 8 min · 1606 words · Khoa

How to test drive view in iOS

Issue #303 Instead of setting up custom framework and Playground, we can just display that specific view as root view controller window.rootViewController = makeTestPlayground() func makeTestPlayground() -> UIViewController { let content = UserCell() content.nameLabel.text = "Thor" content.streetLabel.text = "Asgard" content.weaponLabel.text = "Hammer" let viewController = UIViewController() viewController.view.backgroundColor = .white viewController.view.addSubview(content) NSLayoutConstraint.on([ content.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor), content.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor), content.widthAnchor.constraint(equalTo: viewController.view.widthAnchor, multiplier0.9), content.heightAnchor.constraint(equalToConstant: 200) ] return viewController }

June 12, 2019 · 1 min · 64 words · Khoa

How to make carousel layout for UICollectionView in iOS

Issue #302 Based on AnimatedCollectionViewLayout final class CarouselLayout: UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil } guard let collectionView = collectionView else { return nil } return attributes.map({ transform(collectionView: collectionView, attribute: $0) }) } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } private func transform(collectionView: UICollectionView, attribute: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { let a = attribute let width = collectionView....

June 12, 2019 · 3 min · 635 words · Khoa

How to make simple pan to dismiss view in iOS

Issue #301 Make it more composable using UIViewController subclass and ThroughView to pass hit events to underlying views. class PanViewController: UIViewController { var animator = UIViewPropertyAnimator(duration: 0, curve: .easeOut) lazy var panGR = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_: ))) let slideView = UIView() let gripView = UIView() var options: Options = Options() var didHide: (() -> Void)? let pullDownVelocity: CGFloat = 70 class Options { var contentView: UIView = UIView() var percentHeight: CGFloat = 0....

June 12, 2019 · 2 min · 306 words · Khoa

Getting started with WWDC 2019

Issue #300 WWDC WWDC special WWDC by Sundell NSHipster WWDC 2019 WWDC 2019 - The Things You May Have Missed 7 essential WWDC session videos for iOS developers The 15 Best WWDC Videos of All Time WWDC Extracted gists Favorite WWDC 2019 sessions Swift 5.1 Property wrappers to remove boilerplate code in Swift Understanding Opaque Return Types in Swift The Swift 5.1 features that power SwiftUI’s API What’s new in Swift 5....

June 11, 2019 · 1 min · 201 words · Khoa

How to style NSButton in AppKit

Issue #297 let button = NSButton() button.wantsLayer = true button.isBordered = false button.setButtonType(.momentaryChange) button.attributedTitle = NSAttributedString( string: "Click me", attributes: [ NSAttributedString.Key.foregroundColor: NSColor.white, NSAttributedString.Key.font: NSFont.labelFont(ofSize: 13) ] button.layer?.backgroundColor = NSColor.orange.cgColor button.layer?.cornerRadius = 12 activate( button.anchor.height.equal.to(32), button.anchor.width.equal.to(100) ) To make it have native rounded rect button.imageScaling = .scaleProportionallyDown button.setButtonType(.momentaryPushIn) button.bezelStyle = .rounded button.isBordered = true import AppKit import Omnia extension NSButton { func style(imageName: String) { image = NSImage(named: NSImage.Name(imageName)) isBordered = false imageScaling = ....

May 31, 2019 · 1 min · 102 words · Khoa

How to highlight selection of NSCollectionViewItem

Issue #296 Original answer https://stackoverflow.com/a/54793979/1418457 In your NSCollectionViewItem subclass, override isSelected and change background color of the layer. Test in macOS 10.14 and Swift 4.2 class Cell: NSCollectionViewItem { override func loadView() { self.view = NSView() self.view.wantsLayer = true } override var isSelected: Bool { didSet { self.view.layer?.backgroundColor = isSelected ? NSColor.gray.cgColor : NSColor.clear.cgColor } } }

May 30, 2019 · 1 min · 57 words · Khoa

How to add indicator under tab bar buttons in iOS

Issue #288 selectionIndicatorImage https://developer.apple.com/documentation/uikit/uitabbar/1623456-selectionindicatorimage Should design image with enough height, transparent background and indicator at the bottom Use this property to specify a custom selection image. Your image is rendered on top of the tab bar but behind the contents of the tab bar item itself. The default value of this property is nil, which causes the tab bar to apply a default highlight to the selected item Custom UITabBar or UITabBarController Hide existing tabBar tabBar....

May 27, 2019 · 2 min · 374 words · Khoa

Getting to know some pragmatic programming language features

Issue #270 As you know, in the Pragmatic Programmer, section Your Knowledge Portfolio, it is said that Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut. Additionally, learning many languages is far easier now, thanks to the wealth of freely available software on the Internet...

May 23, 2019 · 8 min · 1570 words · Khoa