Post

Replies

Boosts

Views

Created

Focus fails when TextField includes axis: .vertical
I've found another interesting issue with the Focus system. My text case is SwiftUI in Preview or Simulator (using an iPad mini case) -- I haven't tried this on other environments, so your mileage may vary. I have a Form including several TextFields. Adding the usual @FocusState logic, I observe that if I type a TAB key, then (a) If the TextFields are specified using TextField(“label”, text: $text), typing the tab key switches focus from field to field as expected, BUT (b) If the TextFields are specified using TextField(“label”, text: $text, axis: .vertical), typing the tab key adds whitespace to the field and does NOT change focus. In the latter case, I need to use an .onKeyPress(.tab) {….} modifier to achieve the desired result. Reported as FB15432840
0
0
581
Oct ’24
$FocusState and Lists with rows containing TextFields
While I've seen examples of using $FocusState with Lists containing "raw" TextFields, in my use case, the List rows are more complex than that and contain multiiple elements, including TextFields. I obviously don't understand something fundamental here, because I am completely unable to get TextField-to-TextField tabbing to work. Can someone set me straight? Sample code demonstrating the issues: // // ContentView.swift // ListElementFocus // // Created by Richard Aurbach on 10/12/24. // import SwiftUI /// NOTE: in my actual app, the data model is actually a set of SwiftData /// PresistentModel objects. Here, I'm simulating them with an Observable. @Observable final class TestModel: Identifiable { public var id: UUID public var checked: Bool = false public var title: String = "Test" public var subtitle: String = "Subtitle" init(checked: Bool = false, title: String, subtitle: String) { self.id = UUID() self.checked = checked self.title = title self.subtitle = subtitle } } struct ContentView: View { /// Instead of a @Query... @State var records: [TestModel] = [ TestModel(title: "First title", subtitle: "blah, blah, blah"), TestModel(title: "Second title", subtitle: "more nonsense"), TestModel(title: "Third title", subtitle: "even more nonsense"), ] @FocusState var focus: UUID? var body: some View { Form { Section { HStack(alignment: .top) { Text("Goal:").font(.headline) Text( "If a user taps in the TextField in any row, they should be able to tab from row to row using any keyboard which supports a tab key." ) } HStack(alignment: .top) { Text("#1:").font(.headline) Text( "While I will admit that this code is probaby total garbage, I haven't been able to find any way to make tabbing from row to row to work at all." ) } HStack(alignment: .top) { Text("#2:").font(.headline) Text( "Tapping the checkbox button causes the row to flash with the current accent color, and I can't find any way to turn that off." ) } } header: { Text("Problems").font(.title3).bold() }.headerProminence(.increased) Section { List(records) { record in ListRow(record: record, focus: focus) .onKeyPress(.tab) { focus = next(record) return .handled } } } header: { Text("Example: Selector of Editable Items").font(.title3).bold() }.headerProminence(.increased) } .padding() } private func next(_ record: TestModel) -> UUID { guard !records.isEmpty else { return UUID() } if record.id == records.last!.id { return records.first!.id } if let index = records.firstIndex(where: { $0.id == record.id }) { return records[index + 1].id } return UUID() } } struct ListRow: View { @Bindable var record: TestModel var focus: UUID? @FocusState var focusState: Bool init(record: TestModel, focus: UUID?) { self.record = record self.focus = focus self.focusState = focus == record.id } var body: some View { HStack(alignment: .top) { Button { record.checked.toggle() } label: { record.checked ? Image(systemName: "checkmark.square.fill") : Image(systemName: "square") }.font(.title2).focusable(false) VStack(alignment: .leading) { TextField("title", text: $record.title).font(.headline) .focused($focusState) Text("subtitle").italic() } } } } #Preview { ContentView() }
0
0
489
Oct ’24
SwiftData Query and optional relationships
Xcode 16.2 (16C5032a) FB16300857 Consider the following SwiftData model objects (only the relevant portions are shown) (note that all relationships are optional because eventually this app will use CloudKit): @Model final public class Team { public var animal: Animal? public var handlers: [Handler]? ... } @Model final public class Animal { public var callName: String public var familyName: String @Relationship(inverse: \Team.animal) public var teams: [Team]? ... } @Model final public class Handler { public var givenName: String @Relationship(inverse: \Team.handlers) public var teams: [Team]? } Now I want to display Team records in a list view, sorted by animal.familyName, animal.callName, and handlers.first.givenName. The following code crashes: struct TeamListView: View { @Query<Team>(sort: [SortDescriptor(\Team.animal?.familyName), SortDescriptor(\Team.animal?.callName), SortDescriptor(\Team.handlers?.first?.givenName)]) var teams : [Team] var body: some View { List { ForEach(teams) { team in ... } } } } However, if I remove the sort clause from the @Query and do the sort explicitly, the code appears to work (at least in preliminary testing): struct TeamListView: View { @Query<Team> var teams: [Team] var body: some View { let sortedTeams = sortResults() List { ForEach(sortedTeams) { team in ... } } } private func sortResults() -> [Team] { let results: [Team] = teams.sorted { team1, team2 in let fam1 = team1.animal?.familyName ?? "" let fam2 = team2.animal?.familyName ?? "" let comp1 = fam1.localizedCaseInsensitiveCompare(fam2) if comp1 == .orderedAscending { return true } if comp1 == .orderedDescending { return false } ... <proceed to callName and (if necessary) handler givenName comparisons> ... } } } While I obviously have a workaround, this is (in my mind) a serious weakness in the implementation of the Query macro.
5
0
813
Jan ’25
How to control when a DatePicker "pops up"
I have a Date field that holds the scheduled start date for an activity.. However, activities can be unscheduled (i.e., waiting to be scheduled at some other time). I want to use Date.distantFuture to indicate that the activity is unscheduled. Therefore I am looking to implement logic in my UI that looks something like @State private var showCalendar: Bool = false if date == .distantFuture { Button("unscheduled") { showCalendar.toggle() }.buttonStyle(.bordered) } else { DatePicker(section: $date) } .popover(isPresented: $showCalendar) { <use DatePicker Calendar view> } But this approach requires that I access the DataPicker's Calendar view and I don't know how to do that (and I don't ever what my users to see "Dec 31, 4000"). Any ideas? (BTW, I have a UIKit Calendar control I could use, but I'd prefer to use the standard control if possible.)
4
0
111
Mar ’25
Automatic Code Signing Error
I am trying to update an old UIKit/CoreData app and am (among other changes) adding CloudKit synchronization support. I enabled CloudKit (ie, set up a new CloudKit domain, enabled CloudKit, Background Mode Remote Notifications, and Push Notifications. When I did this, automatic code signing failed. (see attached for the messages). I tried creating and downloading a new provisioning profile, but that did not help. FB19742743 Can someone help me? I have absolutely no idea of what to do next to get this app signed (and hopefully back into the AppStore soon).
2
0
222
Aug ’25
"Unwrapping" Scrolling
For a number of complex views in my app, I need to embed scrollable objects (like List, Form or TextEditor) in a ScrollView. To do that, I need to apply a limit to the height of the embedded object. What I would like to do is set that limit to the actual height of the content being displayed in the List, Form, TextEditor, etc. (Note that this height calculation should be dynamic, so that content changes are properly displayed. I attempted the following: @State listHeight: CGFloat = .zero List { ... content here } .onScrollGeometryChange(for: CGFloat.self, of: { geometry in return geometry.contentSize.height }, action: { oldValue, newValue in if oldValue != newValue { listHeight = newValue } }) .frame(height: listHeight) .scrollDisabled(true) This does not work because geometry.contentSize.height is always 0. So it is apparent that .onScrollGeometryChangedoes not interact with the internal scrolling mechanism of List. (Note, however, that.scrollDisabled` does work.) Does anyone have a suggestion on how I might get this to work?
3
0
141
Aug ’25
Fous, FocusState and Architecture
I am currently struggling with resolving what appear to be competing design issues, and (while I may be just demonstrating my own ignorance) I would like to share my thoughts in the hope that you may have useful insights. For purposes of discussion, consider a large and complex data entry screen with multiple sections for input. For all of the usual reasons (such as reuse, performance management, etc) each of these sections is implemented as its own, separately-compiled View. The screen is, then, composed of a sequence of reusable components. However, each of these components has internal structure and may contain multiple focusable elements (and internal use of .onKeyPress(.tab) {...} to navigate internally). And the logic of each component is such that it has an internal @FocusState variable defined with its own unique type. So, obviously what I want is on the one hand, to provide a tab-based navigation scheme for the screen as a whole, where focus moves smoothly from one component's internals to the next component, and on the other hand ,to build components that don't know anything about each other and have no cross-component dependencies, so that they can be freely reused in different situations. And that's where I'm stuck. Since focus state variables for different components can have different types, a single over-arching FocusState passed (as a binding) to each component doesn't seem possible or workable. But I don't know how else to approach this issue. (Note: in UIKit, I've done things like this by direct manipulation of the Responder Chain, but I don't see how to apply this type of thinking to SwiftUI.) Thoughts?
3
0
163
Oct ’25
NavigationPath.append but .navigationDestination Not Being Called
I am trying to do a bit of fancy navigation in SwiftUI using NavigationPath and am having a problem. I have a root view with includes a button: struct ClassListScreen: View { @Bindable private var router = AppRouter.shared @State private var addCourse: Bool = false ... var body: some View { ... Button("Add Class") { router.currentPath.append(addCourse) }.buttonStyle(.borderedProminent) ... .navigationDestination(for: Bool.self){ _ in ClassAddDialog { course in sortCourses() } } } } router.currentPath is the NavigationPath associated with the operative NavigationStack. (This app has a TabView and each Tab has its own NavigationStack and NavigationPath). Tapping the button correctly opens the ClassAddDialog. In ClassAddDialog is another button: struct ClassAddDialog: View { @Bindable private var router = AppRouter.shared @State private var idString: String = "" ... var body: some View { ... Button("Save") { let course = ... ... (save logic) idString = course.id.uuidString var path = router.currentPath path.removeLast() path.append(idString) router.currentPath = path }.buttonStyle(.borderedProminent) ... .navigationDestination(for: String.self) { str in if let id = UUID(uuidString: str), let course = Course.findByID(id, with: context) { ClassDetailScreen(course: course) } } } } My intent here is that tapping the Save button in ClassAddDialog would pop that view and move directly to the ClassDetailScreen (without returning to the root ClassListScreen). The problem is that the code inside the navigationDestination is NEVER hit. (I.e., a breakpoint on the if let ... statement) never fires. I just end up on a (nearly) blank view with a warning triangle icon in its center. (And yes, the back button takes me to the root, so the ClassAddDialog WAS removed as expected.) And I don't understand why. Can anyone share any insight here?
0
1
80
Oct ’25