Post

Replies

Boosts

Views

Activity

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.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Dec ’21
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.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
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.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
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.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jan ’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()) } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jan ’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.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’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 } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Feb ’22
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) } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’22
Reply to Passing a Variable Between Two Unrelated Views Without Binding
I guess I've solved a problem on my own again. import SwiftUI struct ContentView: View { @StateObject var monster = MonsterObservable.shared var body: some View { GeometryReader { geo in ZStack { HStack(spacing: 0.0) { RightView() .frame(width: geo.size.width, height: geo.size.height) } ShowDialogView(isShowing: $monster.showDialog) { } .frame(width: 500, height: 600, alignment: .center) .cornerRadius(10.0) } } } } struct ShowDialogView<Content: View>: View { @Binding var isShowing: Bool @ViewBuilder let content: () -> Content var body: some View { Group { if isShowing { ZStack { Color.brown VStack { Spacer() Button { isShowing = false } label: { Text("Close me") .font(.largeTitle) }.padding([.top, .bottom], 100.0) } } } } } } class MonsterObservable: ObservableObject { static let shared = MonsterObservable() @Published var showDialog = false } class GameScore: ObservableObject { static let shared = GameScore() @Published var score = 0 } struct RightView: View { @ObservedObject var monster = MonsterObservable.shared var body: some View { ZStack { Color.red Button { monster.showDialog = true } label: { Text("Change") .font(.largeTitle) } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’22
Reply to Getting an Updated Value Through @EnvironmentObject
import SwiftUI struct ContentView: View { @EnvironmentObject var gameSettings: GameSettings var body: some View { GeometryReader { geo in ZStack { HStack(spacing: 0.0) { RightView().environmentObject(gameSettings) .frame(width: geo.size.width / 2.0, height: geo.size.height) Spacer() } VStack { HStack { Spacer() Button { print("\(gameSettings.score)") } label: { Text("Print") .font(.largeTitle) }.padding(.trailing, 40.0) } Spacer() } } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Mar ’22