Post

Replies

Boosts

Views

Activity

How to detect multiple drag gestures?
Hi, I have a code snippet as below that creates a draggable circle when a drag gesture is performed, and the circle disappears when the drag gesture is released. I'm wondering how I can make it detect multiple drag gestures. More specifically, when a finger is performing drag gesture, if another finger presses the screen at this time, a new circle will be generated. struct ContentView: View { enum DragState { case inactive case active(position: CGPoint) var location: CGPoint { switch self { case .inactive: return .zero case .active(let position): return position } } var isActive: Bool { switch self { case .inactive: return false case .active: return true } } } @GestureState private var state: DragState = .inactive var body: some View { ZStack { Color.clear.contentShape(Rectangle()) if state.isActive { Circle() .frame(width: 100, height: 100) .foregroundStyle(.blue) .position(state.location) } } .gesture(dragGesture) } private var dragGesture: some Gesture { DragGesture(minimumDistance: 0) .updating($state) { value, state, _ in state = value.location == .zero ? .inactive : .active(position: value.location) } } }
3
0
1k
Dec ’23
TabView init(selection:content:) in Xcode 14.3.1
Hi, I have the following code snippet. If I use binding selection in the view model, when I release the swipe gesture, it goes back to "Tab 1", and the "selectedTab" doesn't seem to update automatically. But if I use binding optional selection in the view, then it works as expected. Could someone help me clarify it? struct TabModel: Identifiable, Hashable { let id: Int let name: String } class TabViewModel: ObservableObject { // tabview binding selection @Published var selectedTab: TabModel? var tabs: [TabModel] init() { tabs = [ TabModel(id: 1, name: "Tab 1"), TabModel(id: 2, name: "Tab 2"), TabModel(id: 3, name: "Tab 3") ] } } struct ContentView: View { @ObservedObject var viewModel: TabViewModel // tabview binding selection @State private var selectedTab: TabModel? var body: some View { TabView(selection: $viewModel.selectedTab/$selectedTab) { ForEach(viewModel.tabs) { tab in Text(tab.name) .tag(tab) } } .tabViewStyle(.page) } }
1
0
229
Oct ’23
Implement a Gradual Slowdown in a Random Selection Animation
Hi, I have a code snippet as below that creates a random selection animation. I would like the animation gradually slows down instead of abruptly stopping when the specified duration is reached. I initially attempted to achieve this by using multiple timers with different intervals to represent various animation speeds and then using another timer to trigger these timers. However, I'm not feeling well with this approach and am seeking better suggestions and insights. Any comments and recommendations would be greatly appreciated. @State private var timer: Timer? @State private var elapsedTime: TimeInterval = 0 private let timeInterval: TimeInterval = 0.1 private let duration: TimeInterval = 10 func start() { if timer == nil { timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true) { _ in if elapsedTime < duration { elapsedTime += timeInterval withAnimation(.spring(response: timeInterval)) { // randomly select an item } } else { timer?.invalidate() timer = nil elapsedTime = 0 } } timer?.fire() } }
0
0
235
Sep ’23
Add a button to keyboard in a sheet view in Xcode 15 beta 3
Hello, I am trying to create a simple effect in a sheet view where when a user tap the 'Done' button on keyboard, the 'TextField' should be unfocused and the keyboard should disappear. With almost the same code, the 'Done' button doesn't work as expected in 'SheetView' as it does in 'MainView'. Any suggestions are appreciated. struct MainView: View { @State private var text = "" @FocusState private var isFocused: Bool @State private var showSheet = false var body: some View { VStack { TextField("text", text: $text) .focused($isFocused) .textFieldStyle(.roundedBorder) Button("showSheetView") { isFocused = false showSheet.toggle() } } .padding() .toolbar { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { isFocused = false } } } .sheet(isPresented: $showSheet) { NavigationStack { SheetView() } } } } struct SheetView: View { @Environment(\.dismiss) var dismiss @State private var text = "" @FocusState private var isFocused: Bool var body: some View { TextField("text", text: $text) .focused($isFocused) .textFieldStyle(.roundedBorder) .padding() .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Cancel") { isFocused = false dismiss() } } // The following tool bar button does not work. It seems tappable, but not functioning. ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { isFocused = false } } } } }
1
0
515
Jul ’23
Migrating from the Observable Object protocol to the Observable macro
// Before I was able to do something like: struct ContentView: View { @EnvironmentObject var listData: ListData var body: some View { ListView($listData.listDataArray) } } struct ListView: View { @Binding var listDataArray: [DataType] } class ListData: ObservableObject { @Published var listDataArray: [DataType] = [] } // Now, I will get the error "Cannot find '$listData' in scope" on the line indicated below when I try to migrate to the Observable macro struct ContentView: View { @Environment(ListData.self) var listData var body: some View { ListView($listData.listDataArray) ----------> Error } } struct ListView: View { @Binding var listDataArray: [DataType] } @Observable class ListData { var listDataArray: [DataType] = [] } @main struct SomeApp: App { @State private var listData = ListData() var body: some Scene { WindowGroup { ContentView .environment(listData) } } }
3
0
1.4k
Jun ’23
Actor Isolated Keyword in Xcode 15 Beta
The following code snippets are citied from https://www.avanderlee.com/swift/nonisolated-isolated/ actor BankAccountActor { enum BankError: Error { case insufficientFunds } var balance: Double init(initialDeposit: Double) { self.balance = initialDeposit } func transfer1(amount: Double, to toAccount: BankAccountActor) async throws { guard balance >= amount else { throw BankError.insufficientFunds } balance -= amount await toAccount.deposit(amount: amount) } func transfer2(amount: Double, to toAccount: isolated BankAccountActor) async throws { guard balance >= amount else { --------- first error throw BankError.insufficientFunds } balance -= amount. -------------------- second error toAccount.balance += amount } func deposit(amount: Double) { balance = balance + amount } } Please correct me if I am wrong. My understanding of the 'transfer1' method is that it involves two actor instances. The first instance(self) and the second instance(toAccount). The first instance checks its balance and modify it within its isolated context. However, when calling the deposit method of the second instance, the 'transfer1' method of the first instance is non-isolated for the second instance. By marking transfer1 as async, it becomes an isolated context for the second instance (toAccount), allowing the deposit method to be safely executed within its own actor context. Additionally, I am confused why two error messages appear on the 'transfer2' method. 1st error: Expression is 'async' but is not marked with 'await'. 2nd error: Actor-isolated property 'balance' can not be mutated on a non-isolated actor instance.
1
0
977
Jun ’23
ObservableObject protocol to @Observable macro
// Before class A: ObservableObject { @Published var dataArray: [dataType] } class B: ObservableObject { @Published var dataArray: [dataType] init(a: A) { A.$dataArray .assign(to: &$dataArray) } } // After applying @Observable, I get an error "Cannot find 'A.$anArray' in scope" on the line indicated below. @Observable class A { var dataArray: [dataType] } @Observable class B { var dataArray: [dataType] init(a: A) { A.$dataArray ----------------------------- Error .assign(to: &$dataArray) } } Class A contains an array to store data fetched from an API. I'm trying to extract some contents from class A into class B. Making them focus on different functionality. All functions in Class B also require the downloaded data.
1
0
790
Jun ’23