Post

Replies

Boosts

Views

Activity

Reply to Telling a View to show a Dialog from Another
I guess I've solved my question as follows. import SwiftUI struct ContentView: View { @ObservedObject var monster: MonsterObservable var body: some View { GeometryReader { geo in ZStack { HStack(spacing: 0.0) { LeftView() .frame(width: geo.size.width / 2.0, height: geo.size.height, alignment: .leading) RightView(showMe: $monster.showDialog) .frame(width: geo.size.width / 2.0, height: geo.size.height, alignment: .trailing) } ShowDialogView(isShowing: monster.showDialog) { } .frame(width: 500, height: 600, alignment: .center) .cornerRadius(10.0) } } } } class MonsterObservable: ObservableObject { @Published var showDialog = false } import SwiftUI struct RightView: View { @Binding var showMe: Bool var body: some View { ZStack { Color.red Button { showMe = true } label: { Text("Tap me") .font(.largeTitle) } } } }
Mar ’22
Reply to 'animation' was deprecated in iOS 15.0
I guess I've somehow worked it out as follows. import SwiftUI struct ContentView5: View { @State private var larger = true var body: some View { VStack { Circle() .fill(Color.pink) .frame(width: 150, height: 150) .scaleEffect(larger ? 2 : 1) .animation(.easeInOut(duration: 1).repeatForever(), value: larger) }.onAppear { larger = false } } }
Feb ’22
Reply to Where and How to Create FileManager as a Singleton?
I've figured it out. You use UIApplicationDelegateAdaptor for iOS, NSApplicationDelegateAdaptor for Cocoa. import SwiftUI @main struct MyCrazyApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { ContentView() } } } class AppDelegate: UIResponder, UIApplicationDelegate { let fileManager = FileManager.default } In this fashion, you will access to fileManager in AppDelegate inside another View.
Feb ’22
Reply to Picker with Unexpected Results
I've solved both of the issues with the following. struct PickColorView: View { @State var numberIndex: Int = 4 @State var textSizeIndex: Int = 0 let numbers: [Int] = [14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60] var body: some View { NavigationView { Form { Picker(selection: $numberIndex, label: Text("Numbers")) { ForEach((0...20), id: \.self) { Text("\($0)") } }.onChange(of: numberIndex) { newIndex in print("Index: \(newIndex)") } Picker("Numbers", selection: $textSizeIndex) { ForEach(0..<numbers.endIndex) { index in let number = numbers[index] Text("\(number)") } }.onChange(of: textSizeIndex) { newIndex in print("Index: \(newIndex)") } } .navigationBarTitle("Settings") .navigationBarHidden(false) } .navigationViewStyle(StackNavigationViewStyle()) } }
Jan ’22
Reply to Showing Alert or Sheet after Some Delay?
I've figured out a way of doing it with StateObject. It's something like the following. import SwiftUI import Combine struct ContentView2: View { @State var disabled: Bool = false @StateObject var delayMonitor = DelayMonitor() @State private var showingAlert = false var body: some View { VStack { Spacer() Button("Tap to connect me") { disabled = true delayMonitor.start() } .font(.system(size: 24.0)) .disabled(disabled) Spacer() .frame(height: 30.0) }.onChange(of: delayMonitor.failed) { newValue in print("You've failed?: \(newValue)") disabled = !newValue showingAlert = newValue } .alert("Something is wrong...", isPresented: $showingAlert) { Button("OK", role: .cancel) { } } } } class DelayMonitor: ObservableObject { var timer = Timer() var seconds: Double = 0.0 @Published var failed: Bool = false func start() { timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _ in self.seconds += 1.0 if self.seconds == 5.0 { // arbitrary timeout self.timer.invalidate() DispatchQueue.main.async() { [weak self] in guard let strongSelf = self else { return } strongSelf.failed = true } } }) } } The onChange guy will let me know only if the value (delayMonitor.failed) has changed. Since its initial value is set to false, I'll get a call only if it changes to true.
Jan ’22
Reply to Publishers.CombineLatest in SwiftUI
I guess ObservableObject is a ticket to using Combine in SwiftUI. So I can write the following. import SwiftUI import Combine struct ContentView: View { @State var cancellables = Set<AnyCancellable>() @StateObject var login = Login() @State var canSave: Bool = false var body: some View { VStack { Text("Login") TextField("Enter username", text: $login.user) TextField("Enter password", text: $login.pass) Button("Save") { } .foregroundColor(canSave ? Color.orange : Color.gray) .font(.system(size: 40.0)) .disabled(!canSave) } .padding(.horizontal, 40.0) .onAppear { Publishers.CombineLatest(login.$user, login.$pass) .sink { completion in print(completion) } receiveValue: { (result0, result1) in let bool = (result0.count > 3 && result1.count > 3) canSave = bool }.store(in: &cancellables) } } } class Login: ObservableObject { @Published var user: String = "" @Published var pass: String = "" } This is really good stuff.
Jan ’22
Reply to Publishers.CombineLatest in SwiftUI
I could do something like the following. class ValidateLogin { var good: Bool = false let user: String let pass: String init(user: String, pass: String) { self.user = user self.pass = pass } func validateMe() -> Bool { if user.count > 3 && pass.count > 3 { good = true } return good } } struct ContentView: View { @State var userText: String = "" @State var passText: String = "" @State var canSave: Bool = false var body: some View { ZStack { VStack { TextField("Username", text: $userText) { }.onChange(of: userText) { newValue in let validateLogin = ValidateLogin(user: userText, pass: passText) canSave = validateLogin.validateMe() } SecureField("Password", text: $passText) { }.onChange(of: passText) { newValue in let validateLogin = ValidateLogin(user: userText, pass: passText) canSave = validateLogin.validateMe() } }.padding(.horizontal, 20.0) }.onAppear { //Publishers.CombineLatest($userText, $passText) } } } The code above doesn't involve Combine at all. I want to do it in a Combine way.
Jan ’22
Reply to Horizontal List with NavigationView and NavigationLink
I've solved the problem by having NavigationView before ScrollView like the following. ZStack { VStack { NavigationView { ScrollView(.horizontal, showsIndicators: false) { HStack(alignment: .top, spacing: 0) { ForEach(horizonModels, id: \.self) { model in if model.id == 0 { NavigationLink(model.name) { MenuView0() } .font(.system(size: 20.0)) .padding(.horizontal, 20.0) .foregroundColor(Color.white) } else { NavigationLink(model.name) { MenuView1() } .font(.system(size: 20.0)) .padding(.horizontal, 20.0) .foregroundColor(Color.white) } } } } .frame(height: 40.0) .background(Color.orange) } } } That's kind of odd to me.
Dec ’21
Reply to Sign in with Apple not working on Xcode 13 simulators
I've tested my sample app with Apple Sign In with two simulators. They don't go further after I enter my password. When I tested it for a macOS application two weeks ago, I ended up restarting my iMac. The same is true for an iOS sample that I created at the same time. I had to restart my iPhone. Anyway, in your case, I wouldn't be worried as long as it works on an actual device. Some features simply don't work with the simulator.
Dec ’21
Reply to Using Combine-Future to Fetch Server Data
I guess the following is better. But I'm not completely satisfied. // ViewController // import UIKit import Combine class ViewController: UIViewController { // MARK: - Variables var cancellable: AnyCancellable? private var cancellableSet: Set<AnyCancellable> = [] // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() let urlStr = "https://api.github.com/repos/ReactiveX/RxSwift/events" let viewModel = ViewModel(urlStr: urlStr, waitTime: 7.0) viewModel.fetchData(urlText: viewModel.urlStr, timeInterval: viewModel.waitTime) .sink { completion in print("Done!") } receiveValue: { dataModels in print("Count: \(dataModels.count)") } .store(in: &cancellableSet) } } // ViewModel // import UIKit import Combine class ViewModel { var anycancellables = Set<AnyCancellable>() var urlStr: String var waitTime: Double init(urlStr: String, waitTime: Double) { self.urlStr = urlStr self.waitTime = waitTime } func fetchData(urlText: String, timeInterval: Double) -> Future<[DataModel], Error> { return Future<[DataModel], Error> { promise in let url = URL(string: urlText)! var request = URLRequest(url: url) request.timeoutInterval = timeInterval let sessionConfiguration = URLSessionConfiguration.default let session = URLSession(configuration: sessionConfiguration) session.dataTask(with: request) { data, response, error in if let error = error { print("error: \(error.localizedDescription)") promise(.failure("Failure" as! Error)) } if let jsonData = data { do { let dataModels = try JSONDecoder().decode([DataModel].self, from: jsonData) promise(.success(dataModels)) } catch { print("Error while parsing: \(error)") } } }.resume() } } }
Dec ’21