I've read all previous posts on this topic but none seem to address what I'm seeing for iOS 16 and using NavigationStack. I'm also using an overall @EnvironmentObject for navigation state.
I have a split view app. In the detail section, I have a NavigationStack surrounding the detail view. Within the detail view (MyView), there is a base view with a "+" button in the toolbar to create a new entity.
That opens NewEntityView where I show a grid of buttons for the user to select a type to create a new entity before moving to NewEntityView to fill in the details for the entity. The top row of the grid of buttons takes the user straight to the NewEntityView with a NavigationLink. These work fine.
The next row of buttons present a menu of sub-types and then should take the user to the NewEntityView view. These buttons do not work.
Code (simplified to not have clutter):
SplitViewDetailView:
struct SplitViewDetailView: View {
@EnvironmentObject var navigationManager: NavigationStateManager
@Binding var selectedCategory: Route?
var body: some View {
NavigationStack(path: $navigationManager.routes) {
// other irrelevant stuff
MyView()
}
.environmentObject(navigationManager)
.navigationDestination(for: Route.self) { $0 }
}
}
MyView:
struct MyView: View {
@EnvironmentObject var navigationManager: NavigationStateManager
var body: some View {
List {
// other stuff
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {}, label: {
NavigationLink(value: Route.newTypeSelect) {
Image(systemName: "plus")
.frame(width: 44, height: 44)
}
} )
}
}
.navigationDestination(for: Route.self) { $0 }
}
SelectTypeView:
struct SelectTypeView: View {
var body: some View {
ZStack {
VStack {
// Top row with no subtypes
HStack {
ForEach (topRows, id: \.self) { type in
NavigationLink(value: Route.newEntityDetails(type.rawValue)) { <-- these work
Text(type)
}
}
}
HStack {
ForEach (middleRow, id: \.self) { type in
Menu {
ForEach (subtype[type], id: \.self) { sub in
NavigationLink(value: Route.newEntityDetails(sub.rawValue)) { <-- these go nowhere
Text(sub)
}
}
} label: {
Text(type)
}
}
}
}
}
}
}
NavigationStateManager:
class NavigationStateManager: ObservableObject {
@Published var routes = [Route]()
// other stuff
}
And Route:
enum Route: Identifiable {
var id: UUID { UUID() }
case newTypeSelect
case newEntityDetails(String)
}
extension Route: View {
var body: some View {
switch self {
case .newTypeSelect:
SelectTypeView()
case .newEntityDetails(let type):
NewEntityView(selectedType: type)
}
}
}
The menus show up fine but tapping on an item does nothing. I've attempted to wrap the menu in its own NavigationStack but that is rejected stating it is already in one defined by a parent view. I've tried making the links Buttons with destinations and those are also rejected.
What is the newest/best way to present a menu with NavigationLinks? One doesn't simply wrap the menu in a NavigationView if one is using a NavigationStack?
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
I am using the TabView control in SwiftUI on a tvOS 18 target with the style of sidebarAdaptable. When I have 7 or less tabs things operate correctly. When I add an 8th tab and you navigate to the contents of the tab the menu collapses as expected but you cannot navigate back to restore the menu. This code reproduces the issue:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Tab("Tab1", systemImage: "person.circle") {
Button("Button1") {}
}
Tab("Tab2", systemImage: "person.circle") {
Button("Button2") {}
}
Tab("Tab3", systemImage: "person.circle") {
Button("Button3") {}
}
Tab("Tab4", systemImage: "person.circle") {
Button("Button4") {}
}
Tab("Tab5", systemImage: "person.circle") {
Button("Button5") {}
}
Tab("Tab6", systemImage: "person.circle") {
Button("Button6") {}
}
Tab("Tab7", systemImage: "person.circle") {
Button("Button7") {}
}
Tab("Tab8", systemImage: "person.circle") {
Button("Button8") {}
}
}
.tabViewStyle(.sidebarAdaptable)
}
}
If you eliminate Tab 8 the problem goes away. You can navigate back to the menu by moving to the left.
Notably the Destination Video sample also reproduces this issue:
https://developer.apple.com/documentation/visionos/destination-video
To reproduce:
Load the above code or Destination Video sample.
Navigate right (click right on remote or swipe right). Menu dismisses and just shows the item you have selected in the upper left corner.
Try to navigate left by clicking left on the remote or swiping left. It looks like the collapsed menu gets focus briefly, screen elements flash but the focus remains outside the menu.
Has anyone else encountered this issue?
In a TabView with the .sidebarAdaptable style, including TabSection elements prevents the default back swipe on the remote from revealing the sidebar. Removing all TabSection elements and using only Tab elements makes it work as expected:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
TabSection("Section") {
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
Tab("Tab", systemImage: "square.fill") { Button(action: {}) { Text("Button") } }
}
}.tabViewStyle(.sidebarAdaptable)
}
}
Am I using it wrong, or is this a bug?
SWIFTUI - update an Array/property Element gives error (had to replace the Whole structure), not sure my syntax is correct
and Gives Syntax error..
Cannot assign value of type 'Double' to type 'Binding' , snippet of code below
BTW, I was able to use
AllObjects.Replace (but it is process intensive & hanges )
.. replaceSubrange(index...index, with:
[TestObjects(..
latitude:Double(-999.0)
//... etc
)]
Perhaps My syntax has issue .. please help
//code snippets
//declaration
@State private var AllObjects:[TestObjects] = []
func TestObjUpdateLoc(index:Int32) {
AllObjects.TestObjects[index].latitude = Double(-999.0)
**//error ..Cannot assign value of type 'Double' to type 'Binding' **
}
// TestObjects
struct TestObjects: Codable, Hashable {
let seq_id:Int32
let latitude:Double
let longitude:Double
// Many more...
}
I have found a system bug with UINavigationController, UIGestureRecognizerDelegate mainly the swipe back control.
I have reproduced this in many apps, while some that use custom swipe back i can not reproduce, however any app using default uikit/swift transitions i can reproduce the flicker/previous screen flashing
The Bug: a slight tap or series of quick taps anywhere on the screen (with the slightest (1-2pt -x)confuse the system into thinking its a swipe back gesture, however instead of pushing back to previous screen the UI flickers and flashes the previous screen. for a split second, very easy to reproduce.
on screens with lots of options of boxes to tap it happens quite often.
I have removed all custom "swipe back from anywhere" logic, all custom gesture logic, and can still reproduce by tapping the edge of the screen
with only UINavigationController, UIGestureRecognizerDelegate in my navigation controller.
Please let me know the best way to get in contact with someone at apple to either build an extension to prevent this flicker or if a developer has a fix but this is rarely talked about. (velocity limits etc do not work, and just make the gesture feel awful)
all the developers i have reached out too have looked into this and have said "its an ios bug, only fix is build a custom swipe back from anywhere, or wait for apple to fix it).... as a small indie app, building my own seems daunting
Recap: quick or taps with small x movement flash previous screen instead of pushing back or simply recognizing it as a tap and not flashing previous screen. this happens with no custom code default uikit/swift. Link me your app i can probably reproduce it, I have reproduced it in X(was hard), Retro(easy), and many more.
The goal is to have a smooth native swipe/drag back from anywhere gesture while preventing flicking on fast taps or short taps with minor x movement. i have tried everything from setting limits to -x, velocity limits etc. nothing fixes this.
happy hacking!
PS i hope someone at apple calls me and i can explain this and we can fix it for every app in an update.
Here’s a clearer and more concise version of your question:
I’m creating an AppIntent to allow users to log their body weight. My intent includes a @Parameter defined as:
@Parameter(
title: "Weight",
description: "Current Weight",
defaultUnit: .pounds,
supportsNegativeNumbers: false
)
var weight: Measurement<UnitMass>
This works but doesn’t respect the user’s Locale and its measurementSystem. When I add defaultUnitAdjustForLocale: true to the @Parameter macro, the default always switches to kilograms, regardless of the locale.
How can I correctly set the default unit to match the user’s locale for the purpose of entering a users body weight?
Hello everyone,
I am a beginner in programming and recently encountered an interesting issue in SwiftUI. (I must admit that it might not be a bug and could simply be due to my lack of understanding.)
I have extracted the relevant code that causes this behavior. Here's the code:
struct BugView: View {
var body: some View {
List {
VStack {
Button("Bug") {
print("1")
}
Button("Bug") {
print("2")
}
Button("Bug") {
print("3")
}
}
}
}
}
In this view, clicking any of the buttons results in all of them being triggered simultaneously. As a result, the console outputs:
1
2
3
I would appreciate it if someone could help me understand why this happens and how to fix it. Thanks in advance!
I feel like I must be missing something dumb, but I can't figure it out. I'm trying to create a modifier to make items resizable by dragging on the corner (I haven't actually implemented the corner part yet though so dragging anywhere on the object resizes it). However the rate that I'm dragging at is different from the rate that the object is resizing. It's also different for horizontal and vertical translation (the horizontal change is smaller than the rate that I'm dragging while the vertical change is larger).
Any help would be greatly appreciated!
Here's my code for the modifier:
struct Resizable: ViewModifier {
@State var size: CGSize = CGSize(width: 500, height: 500)
@State var activeSize: CGSize = .zero
func body(content: Content) -> some View {
content
.frame(width: abs(size.width + activeSize.width), height: abs(size.height + activeSize.height))
// offset is so the top right corner doesn't move
.offset(x: -abs(size.width + activeSize.width) / 2, y: abs(size.height + activeSize.height) / 2)
.gesture(
DragGesture()
.onChanged { gesture in
activeSize.width = -gesture.translation.width
activeSize.height = gesture.translation.height
}
.onEnded { _ in
size.width += activeSize.width
size.height += activeSize.height
activeSize = .zero
}
)
}
}
extension View {
func resizable(maxSize: CGSize = .zero) -> some View {
modifier(Resizable())
}
}
And it is used like so:
struct ContentView: View {
var body: some View {
Rectangle()
.fill(Color.blue)
.resizable()
}
}
Trying to use new Swift @Observable to monitor GPS position within SwiftUI content view. But how do I tie the latest locations to the SwiftUI Map's mapCameraPosition?
Well ideally the answer could cover:
How to fix this error - So get map tracking along with the User Position, but also
How to include facility to turn on/off the map moving to track the user position (which I'll need to do next). So could be tracking, then disable, move map around and have a look at things, then click button to start syncing the mapcameraposition to the GPS location again
Refer to error I'm embedded in the code below.
import SwiftUI
import MapKit
@Observable
final class NewLocationManager : NSObject, CLLocationManagerDelegate {
var location: CLLocation? = nil
private let locationManager = CLLocationManager()
func startCurrentLocationUpdates() async throws {
if locationManager.authorizationStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
for try await locationUpdate in CLLocationUpdate.liveUpdates() {
guard let location = locationUpdate.location else { return }
self.location = location
}
}
}
struct ContentView: View {
var newlocationManager = NewLocationManager()
@State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion(
center: newlocationManager.location?.coordinate ?? <#default value#>,
span: MKCoordinateSpan(latitudeDelta: 0.25, longitudeDelta: 0.25)
))
// GET ERROR: Cannot use instance member 'newlocationManager' within property initializer; property initializers run before 'self' is available
var body: some View {
ZStack {
Map(position: $cameraPosition)
Text("New location manager: \(newlocationManager.location?.description ?? "NIL" )") // works
}
.task {
try? await newlocationManager.startCurrentLocationUpdates()
}
}
}
#Preview {
ContentView()
}
Hi everyone, I am a new developer.
I am writing some code in swift playgrounds and came across some odd errors. I have looked for solutions and have found nothing. If any more experienced developers could point me in the right direction, that would be great.
I am really confused by some of the new data returned in WeatherKit for iOS 18.
The visibility (of an object) was already being returned in HourWeather as a Measurement.
iOS 18 added max/min visibility (of terrain) in DayWeather. BUT instead of a Measurement it's just a Double.
HourWeather:
/// The distance at which an object can be clearly seen.
///
/// The amount of light and weather conditions like fog, mist, and smog affect visibility.
public var visibility: Measurement<UnitLength>
DayWeather's comment:
/// The maximum distance at which terrain is visible for the day.
///
/// The amount of light, and weather conditions like fog, mist, and smog affect visibility.
@available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *)
public var maximumVisibility: Double
This makes it sound like the new items are also a distance and not a percentage.
Why wasn't Measurement used so the unit would be clear? Documentation doesn't explain this either. I'm hoping that this isn't being returned in the unit used by the current locale because my app lets you specify what unit to use for temperature, length, etc regardless of locale. Since all the temperature, length, etc data returned had used Measurement that was possible.
The iOS weather app refers to the lowest/highest visibility in my preferred unit, which is miles.
When I use the following code
List {
ForEach(data.items, id: \.knowledgeInfo.mediaID) { item in
SelectableKnowledgeListItem(knowledgeData: item, baseID: data.knowledgeBaseID, isSelectionMode: $isSelectionMode, selectedItems: $selectedItems)
.KnowledgeListItemStyle()
}
// 添加底部加载更多
if !data.isEnd && !isRefreshing {
ProgressView()
.frame(maxWidth: .infinity, alignment: .center)
.onAppear {
self.isRefreshing = true
manager.getKnowledgeList(knowledgeBaseID: data.knowledgeBaseID, completion: {
self.isRefreshing = false
})
}
}
}
.animation(.interactiveSpring)
.scrollContentBackground(.hidden)
.environment(\.defaultMinListHeaderHeight, 7)
The number of Views rendered in the List remains unchanged after he adds an item to data.items (data is an ObservedObject, items is Published) at runtime.When I removed .animation(.interactiveSpring), it would be processed normally.And if I perform a delete operation after adding, it will cause a crash.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the collection view after the update (11) must be equal to the number of sections contained in the collection view before the update (10), plus or minus the number of sections inserted or deleted (1 inserted, 1 deleted).
Hi,
I have the following swiftUI code:
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
.colorEffect(ShaderLibrary.AlphaConvert())
and the following shader:
[[ stitchable ]] half4 AlphaConvert(float2 position, half4 currentColor) {
return half4(currentColor.r>0.5,currentColor.r<=0.5,0,(currentColor.r>0.5));
}
I am loading a full-res image from my photo library (24MP)... The image initially displays fine, with portions of the image red, and the rest black (due to alpha blending)... However, after rotating the device, I get an image that is a combination of red&green... Note, that the green pixels from the shader have alpha 0, hence, should never be seen. Is there something special that needs to be done on orientation changes so that the shader works fine?
On a ScrollView+LazyVStack, the addition of .scrollTargetLayout causes many list items to be initialized, instead of the ordinary economical behavior of LazyVStack, where only the necessary items and views are initialized. Even worse, as the stack is scrolled down, all list items are reinitialized for every small scroll.
Without, .scrollTargetLayout, everything works fine.
I've tried every variation of locating modifiers, and different ways of identifying the list items, with no success.
Any ideas? Thanks.
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Post.created, ascending: true)],
animation: .default)
private var posts: FetchedResults<Post>
var body: some View {
ZStack{
ScrollView{
LazyVStack(spacing:0) {
ForEach(posts, id: \.self) { post in
PostView(post: post)
}
.onDelete(perform: deletePosts)
}.scrollTargetLayout() // <---- causes multiple Posts re-instantiations for any small scroll, very slow
}
.scrollPosition(id: $scrolledID)
.scrollTargetBehavior(.paging)
Hi! After upgrading to Xcode 16.1 my watchOS app is getting below error using a DatePicker configured with: displayedComponents: .hourAndMinute. I cannot find a solution for this error/warning. It only appears when im using : .hourAndMinute or : .hourAndMinuteandSeconds, but not .date. Note! My code is unchanged only change I Xcode upgrade. Any suggestions?
ForEach<Array, Array, _ConditionalContent<_ConditionalContent<_ConditionalContent<_ConditionalContent<YearPicker, MonthPicker>, _ConditionalContent<DayPicker, ComponentPicker>>, _ConditionalContent<_ConditionalContent<ComponentPicker, ComponentPicker>, _ConditionalContent<AMPMPicker, ModifiedContent<Text, _PaddingLayout>>>>, EmptyView>>: the ID [":"] occurs multiple times within the collection, this will give undefined results!
import SwiftUI
import WidgetKit
struct TimeEditView: View {
let title: String
@Binding var storedValue: String
var body: some View {
Form {
DatePicker(
title,
selection: Binding<Date>(
get: { Date.from(storedValue) ?? Date() },
set: { newDate in
storedValue = newDate.toString()
}
),
displayedComponents: .hourAndMinute
)
.onChange(of: storedValue) {
WidgetCenter.shared.reloadAllTimelines()
print("Morning Start changed!")
}
}
.navigationTitle(title)
}
}
There seems to be a performance issue when scrolling using the track pad with SwiftUI scroll views in macOS 15. This issue is NOT present in macOS 14.
When using the track pad the scrolling is not smooth, but "stutters". However scrolling using the scroll bars is very smooth. The "stuttering" is worse if the SwiftUI ScrollView is in the detail view of a NavigationSplitView.
The problem is not noticeable in scroll views with a small number views, but when the more views inside the scroll view, the more prominent the problem becomes.
I have a simple example app that illustrates the problem here (the example app is a simplification of my app Yammixer): https://github.com/danwaltin/SwiftUIScrollViewPerformance
When running this example app on macOS 14 (Sonoma) on an Intel i7 Mac book pro from 2019 the scrolling is "buttery smooth".
But on macOS 15 (Sequoia) on my Apple Silicon M1 Mac book pro the issue is very obvious.
When using Instruments I see that on macOS 15 "flame graph" shows that 85% of the execution time is in a "_hitTestForEvent" method. If the test app does not use NavigationSplitView about 70% of execution time is in the _hitTestForEvent method.
After a lot of testing and diagnosing, I found that when going to a item creation page, creating an item, navigating back to a TabView with a tabViewStyle of PageTabViewStyle and a navigationTitle that is displaying that data, and all inside of a NavigationStack, the app hangs. I have tested this on iOS 18.2, on both a simulator and a physical iPhone 16 Pro Max, and it always hangs, not crashing. However, when run on My Mac (Designed for iPad) and the iPad simulator, it doesn't crash.
This could just be a really niche problem, but it might be the result of some other issue that could cause other problems.
I have created a minimal reproducible example, stemming from the iOS App template, with SwiftUI and SwiftData.
ContentView.swift
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
NavigationStack {
TabView {
ForEach(items) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .automatic))
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink {
Button(action: {
modelContext.insert(Item(timestamp: Date()))
}) {
Text("Create Item")
}
} label: {
Text("Creation Page")
}
}
}
// When added, crashes the app
.navigationTitle("Crash")
}
}
}
TestingApp.swift (unchanged)
import SwiftUI
import SwiftData
@main
struct TestingApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Item.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
Item.swift (unchanged)
import Foundation
import SwiftData
@Model
final class Item {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
I am not able to use SwiftUI Preview
Here is the report I get while trying to see the issue:
Here is the report of the issue:
And here is the call and code preview:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
#Preview {
ContentView()
}
Please update.
Hey everyone!
I’m encountering an issue while attempting to animate height changes of the content inside safeAreaInset(edge:alignment:spacing:content:).
When animating a reduction in the frame height, the container view (in my case, Map) also animates unexpectedly.
However, when animating an increase in the frame height, the animation works smoothly, and the Map view remains still.
How can I address this odd resizing behavior of the container?
Code:
struct MapView: View {
var body: some View {
Map()
.safeAreaInset(edge: .bottom) {
MapDetailView()
}
}
}
struct MapDetailView: View {
@State private var oldHeightOffset: CGFloat = 0
@State private var newHeightOffset: CGFloat = 0
@State private var containerHeight: CGFloat = 0
private var drag: some Gesture {
DragGesture(coordinateSpace: .global)
.onChanged { value in
withAnimation(.interactiveSpring) {
newHeightOffset = oldHeightOffset + value.translation.height
}
}
.onEnded { value in
switch newHeightOffset {
case containerHeight * 0.625...containerHeight:
withAnimation(.spring) {
newHeightOffset = containerHeight * 0.75
}
case containerHeight * 0.25..<containerHeight * 0.625:
withAnimation(.spring) {
newHeightOffset = containerHeight * 0.5
}
case 0..<containerHeight * 0.25:
withAnimation(.spring) {
newHeightOffset = 0
}
default:
break
}
oldHeightOffset = newHeightOffset
}
}
var body: some View {
NavigationStack {
Rectangle()
.fill(.clear)
.containerBackground(.ultraThinMaterial, for: .navigation)
}
.gesture(drag)
.containerRelativeFrame(.vertical) { length, _ in
length - newHeightOffset
}
.onGeometryChange(for: CGFloat.self) { geometryProxy in
let frame = geometryProxy.frame(in: .local)
return frame.height + newHeightOffset
} action: { containerHeight in
self.containerHeight = containerHeight
}
}
}
Reducing safe area inset's content height (drag down):
Increasing safe area inset's content height (drag up):
I am working on Agora Voice Call and using CallKit to manage incoming and outgoing calls.
Issue:
When I accept a call, CallKit goes behind my app. I want CallKit to remain in front of my app. Please guide me.