How to make borderless material NSTextField in SwiftUI for macOS

Issue #590 Use custom NSTextField as it is hard to customize TextFieldStyle import SwiftUI struct MaterialTextField: View { let placeholder: String @Binding var text: String @State var isFocus: Bool = false var body: some View { VStack(alignment: .leading, spacing: 0) { BorderlessTextField(placeholder: placeholder, text: $text, isFocus: $isFocus) .frame(maxHeight: 40) Rectangle() .foregroundColor(isFocus ? R.color.separatorFocus : R.color.separator) .frame(height: isFocus ? 2 : 1) } } } class FocusAwareTextField: NSTextField { var onFocusChange: (Bool) -> Void = { _ in } override func becomeFirstResponder() -> Bool { let textView = window?...

January 29, 2020 · 2 min · 231 words · Khoa

How to show localized text in SwiftUI

Issue #533 struct ContentView: View { @Environment(\.locale) var locale: Locale var body: some View { VStack { Text(LocalizedStringKey("hello")) .font(.largeTitle) Text(flag(from: locale.regionCode!)) .font(.largeTitle) } } }

December 9, 2019 · 1 min · 25 words · Khoa

How to use ForEach with ScrollView in SwiftUI

Issue #517 Use ScrollView -> VStack -> ForEach -> Content struct SearchScreen: View { @State var searchObjects: [SearchObject] = [ SearchObject(name: "By name", search: { CountryManager.shared.search(byName: $0) }), SearchObject(name: "By calling code", search: { CountryManager.shared.search(byCallingCode: $0) }), SearchObject(name: "By domain", search: { CountryManager.shared.search(byDomain: $0) }), SearchObject(name: "By language", search: { CountryManager.shared.search(byLanguage: $0) }) ] var body: some View { ScrollView { VStack(alignment: .leading) { ForEach(searchObjects.enumerated().map({ $0 }), id: \.element.name, content: { index, searchObject in VStack(alignment: ....

November 22, 2019 · 1 min · 91 words · Khoa

How to modify data inside array in SwiftUI

Issue #516 Suppose we have an array of SearchObject, and user can enter search query into text property. class SearchObject: ObservableObject { let name: String let search: (String) -> [Country] var text: String = "" init(name: String, search: @escaping (String) -> [Country]) { self.name = name self.search = search } } Although SearchObject is class, when we use ForEach, the changes to passed object won’t be reflected in our array and there is no reload trigger, we need to point to object in array directly, like...

November 22, 2019 · 1 min · 168 words · Khoa

How to use index in SwiftUI list

Issue #515 Use enumerated and id: \.element.name struct CountriesView: View { let countries: [Country] var body: some View { let withIndex = countries.enumerated().map({ $0 }) return List(withIndex, id: \.element.name) { index, country in NavigationLink( destination: CountryView(country: country), label: { VStack(alignment: .leading) { Text(country.name) .styleMultiline() } .paddingVertically() } ) } } }

November 22, 2019 · 1 min · 51 words · Khoa

How to use objectWillChange in Combine

Issue #513 A publisher that emits before the object has changed Use workaround DispatchQueue to wait another run loop to access newValue .onReceive(store.objectWillChange, perform: { DispatchQueue.main.async { self.reload() } }) func reload() { self.isFavorite = store.isFavorite(country: country) } Read more https://forums.swift.org/t/combine-observableobject-in-uikit/28433 https://twitter.com/luka_bernardi/status/1155944329363349504

November 21, 2019 · 1 min · 42 words · Khoa

How to show list with section in SwiftUI

Issue #511 struct CountriesView: View { let groups: [Group] init(countries: [Country]) { self.groups = CountryManager.shared.groups(countries: countries) } var body: some View { List { ForEach(groups) { group in Section( header: Text(group.initial) .foregroundColor(Color.yellow) .styleTitle(), content: { ForEach(group.countries) { country in CountryRow(country: country) } } ) } } } }

November 16, 2019 · 1 min · 48 words · Khoa

How to make full width list row in SwiftUI

Issue #508 We need to use frame(minWidth: 0, maxWidth: .infinity, alignment: .leading). Note that order is important, and padding should be first, and background after frame to apply color to the entire frame struct BooksScreen: View { @ObservedObject var viewModel: BooksViewModel var body: some View { List { ForEach(viewModel.books) { book in RowView(vault: book) } } .listStyle(GroupedListStyle()) } } private struct RowView: View { let book: Book var body: some View { VStack(alignment: ....

November 14, 2019 · 1 min · 94 words · Khoa

How to make full screen TabView in SwiftUI

Issue #507 View extends to the bottom, but not to the notch. We need to add .edgesIgnoringSafeArea(.top) to our TabView to tell TabView to extend all the way to the top. Note that if we use edgesIgnoringSafeArea(.all) then TabView ’s bar will be dragged very down and broken. struct MainScreen: View { init() { UITabBar.appearance().backgroundColor = R.color.barBackground UITableView.appearance().backgroundColor = .clear UITableViewCell.appearance().backgroundColor = .clear UITableView.appearance().tableFooterView = UIView() } var body: some View { ZStack { R....

November 14, 2019 · 1 min · 104 words · Khoa

How to fix unable to infer complex closure return type in SwiftUI

Issue #505 Make sure all String are passed into Text, not Optional<String> VStack { Text(data.title) Text(data.description!) Text(data.text!) }

November 13, 2019 · 1 min · 18 words · Khoa

How to make simple Redux for SwiftUI

Issue #502 Mutation is used to mutate state synchronously. Action is like intent, either from app or from user action. Action maps to Mutation in form of Publisher to work with async action, similar to redux-observable AnyReducer is a type erasure that takes the reduce function import Combine import Foundation public protocol Reducer { associatedtype State associatedtype Mutation func reduce(state: State, mutation: Mutation) -> State } public struct AnyReducer<State, Mutation> { public let reduce: (State, Mutation) -> State public init<R: Reducer>(reducer: R) where R....

November 13, 2019 · 2 min · 311 words · Khoa

How to get Binding via dollar prefix in SwiftUI

Issue #488 The dollar is not a prefix, it seems to be a generated code for property wrapper, and each kind of property wrapper can determine which value it return via this dollar sign State and ObservedObject are popular property wrappers in SwiftUI State Read State A persistent value of a given type, through which a view reads and monitors the value. If we have a simple State, we can access its 3 forms...

November 2, 2019 · 3 min · 459 words · Khoa

How to modify state from state in SwiftUI

Issue #487 In case we have to modify state when another state is known, we can encapsulate all those states in ObservableObject and use onReceive to check the state we want to act on. See code Avengers If we were to modify state from within body function call, we will get warnings Modifying state during view update, this will cause undefined behavior. This is similar to the warning when we change state inside render in React...

November 2, 2019 · 6 min · 1172 words · Khoa

How to show loading indicator in SwiftUI

Issue #486 import SwiftUI struct ActivityIndicator: UIViewRepresentable { @Binding var isAnimating: Bool let style: UIActivityIndicatorView.Style func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView { return UIActivityIndicatorView(style: style) } func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) { isAnimating ? uiView.startAnimating() : uiView.stopAnimating() } } struct ActivityIndicator_Previews: PreviewProvider { static var previews: some View { ActivityIndicator(isAnimating: .constant(true), style: .large) } }

November 2, 2019 · 1 min · 55 words · Khoa

How to show image picker in SwiftUI

Issue #485 The easiest way to show image picker in iOS is to use UIImagePickerController, and we can bridge that to SwiftUI via UIViewControllerRepresentable First attempt, use Environment We conform to UIViewControllerRepresentable and make a Coordinator, which is the recommended way to manage the bridging with UIViewController. There’s some built in environment property we can use, one of those is presentationMode where we can call dismiss to dismiss the modal....

November 2, 2019 · 4 min · 667 words · Khoa

How to use array of strings in ForEach in SwiftUI

Issue #483 Every item in list must be uniquely identifiable List { ForEach(books, id: \.bookId) { book in NavigationLink(destination: BookView(book: book) .navigationBarTitle(book.name) ) { VStack { Text(book.name) } } } } In case of primitive, we can just provide id to conform to Identifiable extension String: Identifiable { public var id: String { return self } }

October 31, 2019 · 1 min · 57 words · Khoa

How to make multiline Text in SwiftUI in watchOS

Issue #482 lineLimit does not seem to work, use fixedSize instead Fixes this view at its ideal size. A view that fixes this view at its ideal size in the dimensions given in fixedDimensions. extension Text { func styleText() -> some View { return self .font(.footnote) .foregroundColor(.gray) .lineLimit(10) .fixedSize(horizontal: false, vertical: true) } }

October 31, 2019 · 1 min · 54 words · Khoa

How to reload data without using onAppear in SwiftUI in watchOS

Issue #468 From onAppeear Adds an action to perform when the view appears. In theory, this should be triggered every time this view appears. But in practice, it is only called when it is pushed on navigation stack, not when we return to it. So if user goes to a bookmark in a bookmark list, unbookmark an item and go back to the bookmark list, onAppear is not called again and the list is not updated....

October 17, 2019 · 2 min · 239 words · Khoa

How to use EnvironmentObject in SwiftUI for watchOS

Issue #467 Declare top dependencies in ExtensionDelegate class ExtensionDelegate: NSObject, WKExtensionDelegate { let storeContainer = StoreContainer() func applicationDidEnterBackground() { storeContainer.save() } } Reference that in HostingController. Note that we need to change from generic MainView to WKHostingController<AnyView> as environmentObject returns View protocol class HostingController: WKHostingController<AnyView> { var storeContainer: StoreContainer! override func awake(withContext context: Any?) { super.awake(withContext: context) self.storeContainer = (WKExtension.shared().delegate as! ExtensionDelegate).storeContainer } override var body: AnyView { return AnyView(MainView() ....

October 17, 2019 · 1 min · 179 words · Khoa

How to make container view in SwiftUI

Issue #450 Following the signatures of ScrollView and Group, we can create our own container public struct ScrollView<Content> : View where Content : View { /// The content of the scroll view. public var content: Content } extension Group : View where Content : View { /// The type of view representing the body of this view. /// /// When you create a custom view, Swift infers this type from your /// implementation of the required `body` property....

October 9, 2019 · 2 min · 225 words · Khoa