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 · Khoa Pham

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 · Khoa Pham

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 · Khoa Pham

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 · Khoa Pham

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 · Khoa Pham

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) } } Updated at 2020-09-23 08:42:29...

September 23, 2020 · 1 min · Khoa Pham

How to draw arc corner using Bezier Path

Issue #673 To draw rounded 2 corners at top left and top right, let’s start from bottom left let path = UIBezierPath() // bottom left path.move(to: CGPoint(x: 0, y: bounds.height)) // top left corner path.addArc(withCenter: CGPoint(x: radius, y: radius), radius: radius, startAngle: CGFloat.pi, endAngle: CGFloat.pi * 3 / 2, clockwise: true) // top right corner path.addArc(withCenter: CGPoint(x: bounds.width - radius, y: radius), radius: radius, startAngle: CGFloat.pi * 3 / 2, endAngle: 0, clockwise: true) // bottom right path....

September 15, 2020 · 1 min · Khoa Pham

How to stitch and sort array in Swift

Issue #672 Supposed we want to stitch magazines array into books array. The requirement is to sort them by publishedDate, but must keep preferredOrder of books. One way to solve this is to declare an enum to hold all possible cases, and then do a sort that check every possible combination struct Book { let preferredOrder: Int let publishedDate: Date } struct Magazine { let publishedDate: Date } enum StitchItem { case book(Book) case magazine(Magazine) } func stitch(_ books: [Book], magazines: [Magazine]) -> [StitchItem] { let items = books....

August 28, 2020 · 2 min · Khoa Pham

How to make dynamic font size for UIButton

Issue #671 Use adjustsFontForContentSizeCategory A Boolean that indicates whether the object automatically updates its font when the device’s content size category changes. If you set this property to YES, the element adjusts for a new content size category on a UIContentSizeCategoryDidChangeNotification. button.titleLabel?.adjustsFontForContentSizeCategory = true button.backgroundColor = UIColor.green button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .title1) label.adjustsFontForContentSizeCategory = true label.backgroundColor = UIColor.yellow label.font = UIFont.preferredFont(forTextStyle: .title1) However it seems view (UIButton or UILabel) size is the same, just the inner text increases in size....

August 14, 2020 · 1 min · Khoa Pham

How to test for view disappear in navigation controller

Issue #670 To test for viewWillDisappear during UINavigationController popViewController in unit test, we need to simulate UIWindow so view appearance works. final class PopTests: XCTestCase { func testPop() { let window = UIWindow(frame: UIScreen.main.bounds) let navigationController = UINavigationController() window.rootViewController = navigationController let viewController = DetailViewController() navigationController.viewControllers = [ UIViewController(), viewController ] window.makeKeyAndVisible() let expectation = XCTestExpectation() navigationController.popViewController(animated: false) DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { XCTAssertTrue(viewController.wasDismissed) expectation.fulfill() } wait(for: [expectation], timeout: 1) } } class DetailViewController: UIViewController { override func viewWillDisappear(_ animated: Bool) { super....

August 6, 2020 · 1 min · Khoa Pham