I filed FB15170881 about this. When using .scrollPosition on a view that is inside a .navigationDestination, scrolling the ScrollView causes the content to jump around rather than animate smoothly. The same view placed outside of the .navigationDestination scrolls smoothly as expected.
To view this in action, use the example below. It's apparent on MacOS and iOS, as a Preview or run on-device.
Launch it
It will load to the problematic view by default.
Scroll the view in the square to see the janky movement.
You can also press the "back" button to go to a version of the same view that isn't nested inside a .navigationDestination. This one works smoothly as expected.
import SwiftUI
struct ContentView: View {
let items = [0, 1, 2, 3, 4]
@State private var position = ScrollPosition(idType: Int.self)
@State private var showPage: Bool = true
let height = 300.0
let width = 300.0
var body: some View {
NavigationStack {
VStack {
Text("This scrolls nicely.")
Text("It's at the navigation root.")
demoView
Spacer()
Button(action: {
showPage = true
}) {
Text("Go to broken version")
}
.buttonStyle(.bordered)
.navigationDestination(isPresented: $showPage) {
VStack {
Text("This stutters when scrolling.")
Text("It's in a navigationDestination.")
demoView
Spacer()
}
}
Spacer()
}
}
}
@ViewBuilder var demoView: some View {
let _ = Self._printChanges()
ScrollView(.vertical) {
LazyVStack(spacing: 0) {
ForEach(items, id: \.self) { _ in
Text("Scroll me")
.frame(width: width, height: height)
.border(.pink)
}
}
.scrollTargetLayout()
}
.frame(width: width, height: height)
.border(.blue)
.scrollPosition($position)
}
}
#Preview {
ContentView()
.modelContainer(for: Item.self, inMemory: true)
}
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 trying to build a video editing timeline using SwiftUI which consists of a series of trimmers (sample code for trimmer below). I plan to embed multiple of these trimmers in an HStack to make an editing timeline (HStack in turn will be embedded in a ScrollView). What I want to achieve is that if I trim end of any of these trimmers by dragging it's left/right edge, the other trimmers on timeline should move left/right to fill the gap. I understand as the view shrinks/expands during trimming, there might be a need for spacers on the edges of HStack whose widths need to be adjusted while trimming is ongoing.
Right now the code I have for the trimmer uses a fixed frameWidth of the view, so the view occupies full space even if the trimming ends move. It's not clear how to modify my code below to achieve what I want. This was pretty much possible to do in UIKit by the way.
import SwiftUI
struct SimpleTrimmer: View {
@State var frameWidth:CGFloat = 300
let minWidth: CGFloat = 30
@State private var leftOffset: CGFloat = 0
@State private var rightOffset: CGFloat = 0
@GestureState private var leftDragOffset: CGFloat = 0
@GestureState private var rightDragOffset: CGFloat = 0
private var leftAdjustment: CGFloat {
// NSLog("Left offset \(leftOffset + leftDragOffset)")
var adjustment = max(0, leftOffset + leftDragOffset)
if frameWidth - rightOffset - adjustment - 60 < minWidth {
adjustment = frameWidth - rightOffset - minWidth - 60.0
}
return adjustment
}
private var rightAdjustment: CGFloat {
var adjustment = max(0, rightOffset - rightDragOffset)
if frameWidth - adjustment - leftOffset - 60 < minWidth {
adjustment = frameWidth - leftOffset - 60 - minWidth
}
return adjustment
}
var body: some View {
HStack(spacing: 10) {
Image(systemName: "chevron.compact.left")
.frame(width: 30, height: 70)
.background(Color.blue)
.offset(x: leftAdjustment)
.gesture(
DragGesture(minimumDistance: 0)
.updating($leftDragOffset) { value, state, trans in
state = value.translation.width
}
.onEnded { value in
var maxLeftOffset = max(0, leftOffset + value.translation.width)
if frameWidth - rightAdjustment - maxLeftOffset - 60 < minWidth {
maxLeftOffset = frameWidth - rightAdjustment - minWidth - 60
}
leftOffset = maxLeftOffset
}
)
Spacer()
Image(systemName: "chevron.compact.right")
.frame(width: 30, height: 70)
.background(Color.blue)
.offset(x: -rightAdjustment)
.gesture(
DragGesture(minimumDistance: 0)
.updating($rightDragOffset) { value, state, trans in
state = value.translation.width
}
.onEnded { value in
var minRightOffset = max(0, rightOffset - value.translation.width)
if minRightOffset < leftAdjustment - 60 - minWidth {
minRightOffset = leftAdjustment - 60 - minWidth
}
rightOffset = minRightOffset
}
)
}
.foregroundColor(.black)
.font(.title3.weight(.semibold))
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background {
RoundedRectangle(cornerRadius: 7)
.fill(.yellow)
.padding(.leading, leftAdjustment)
.padding(.trailing, rightAdjustment)
}
.frame(width: frameWidth)
}
}
#Preview {
SimpleTrimmer()
}
Hi,
However I tried to reduce space between list rows in below code I fail, is there any way to reduce this space ?
@State var flag: Bool = false
var myList: [String] = ["Hello", "World", "SwiftUI"]
var body: some View {
VStack(alignment: .leading) {
List (myList, id: \.self) { list in
Text(list)
.border(Color.black)
.font(.system(size: 12)) // Smaller font size
.frame(maxWidth: .infinity, minHeight: 20, alignment: .leading) // Reduced height
.padding(.vertical, 4) // Minimal padding for vertical spacing
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) // Remove insets
.listRowSeparator(.hidden) // Hide separator
}
.listStyle(.plain)
}
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(sysSecondary.opacity(0.4), lineWidth: 1)
)
.frame(width: 220, height:260)
.background(.white)
.clipShape (RoundedRectangle (cornerRadius: 10))
}
}
I'm trying to design a homescreen widget but I am unable to properly control the padding and sizing of various components. In the four attached screenshots you can see the huge variation in padding around the outside, the change in text colour and the spacing between the text. I've boiled it down as simple as possible and attached the view as a sample file.
What I'd like to achieve is a consistent look between iPads and iPhones and ideally in the simulator too. Is there a simple way to set the padding so that all places use the same, and then scale the text so that I know that if the text fits in the simulator the same text will fit on all devices?
Device iPad 8 - 17.7
iPhone 13 Pro Max - 17.7
Xcode Canvas - iPad 13"
Simulator - iPad Pro
sampleview.txt
13"
Xcode 16, iOS 18 official release. On both my phone and simulator, when I build the release build of my app, when I go to control center and select "Add a Control", springboard crashes (see attached crash log).
Somehow this does not happen in debug config, with debug config (which does have a different bundle ID but everything else is the same) I'm able to add the control widget just fine.
The widget code is taken directly from the Apple docs:
struct WidgetTestWidgetControl: ControlWidget {
static let kind: String = "com.myapp.WidgetTestWidget"
var body: some ControlWidgetConfiguration {
AppIntentControlConfiguration(
kind: Self.kind,
provider: Provider()
) { value in
ControlWidgetToggle(
"Start Timer",
isOn: value.isRunning,
action: StartTimerIntent(value.name)
) { isRunning in
Label(isRunning ? "On" : "Off", systemImage: "timer")
}
}
.displayName("Timer")
.description("A an example control that runs a timer.")
}
}
extension WidgetTestWidgetControl {
struct Value {
var isRunning: Bool
var name: String
}
struct Provider: AppIntentControlValueProvider {
func previewValue(configuration: TimerConfiguration) -> Value {
WidgetTestWidgetControl.Value(isRunning: false, name: configuration.timerName)
}
func currentValue(configuration: TimerConfiguration) async throws -> Value {
let isRunning = true // Check if the timer is running
return WidgetTestWidgetControl.Value(isRunning: isRunning, name: configuration.timerName)
}
}
}
struct TimerConfiguration: ControlConfigurationIntent {
static let title: LocalizedStringResource = "Timer Name Configuration"
@Parameter(title: "Timer Name", default: "Timer")
var timerName: String
}
struct StartTimerIntent: SetValueIntent {
static let title: LocalizedStringResource = "Start a timer"
@Parameter(title: "Timer Name")
var name: String
@Parameter(title: "Timer is running")
var value: Bool
init() {}
init(_ name: String) {
self.name = name
}
func perform() async throws -> some IntentResult {
// Start the timer…
return .result()
}
}
However in a fresh project I am able to add this widget code and it works completely fine in both debug and release. How can I fix this?
This is clearly affecting many apps and is the 'fault' of the app, see these threads:
https://www.reddit.com/r/ios/comments/1fiqrd7/ios_18_control_center_keeps_crashing_when_trying/
https://discussions.apple.com/thread/255759997?sortBy=rank
crash-log.txt
Hi,
I have the below code as you can see the list doesn't hide its line separator, so is it a bug ? is there any work around ?
@State var flag: Bool = false
var myList: [String] = ["Hello", "World", "SwiftUI"]
var body: some View {
VStack(alignment: .leading) {
List (myList, id: \.self) { list in
Text(list)
}
.listRowSeparator(.hidden)
.listStyle(.plain)
}
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(sysSecondary.opacity(0.4), lineWidth: 1)
)
.frame(width: 220, height:260)
.background(.white)
.clipShape (RoundedRectangle (cornerRadius: 10))
}
}
When using both the ContactsAccessButton demo project, as well as when implementing it in my own, the whole app freezes after entering a few characters and searching through contacts.
I don't know if this is necessarily reproducable because it's probably related to the contacts in my contact book. Typing in "Lex" does not freeze the app, but typing in "Adam No" freezes it.
I get the following console error before my app freezes and I'm forced to force quit it:
#ContactsButton Failed to get service proxy: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service with pid 3387 named com.apple.ContactsUI.ContactsButtonXPCService" UserInfo={NSDebugDescription=connection to service with pid 3387 named com.apple.ContactsUI.ContactsButtonXPCService}
#ContactsButton Failed to get remote content: nil (got this a number of times
ContactsAccessButton really doesn't seem production ready...
Okay I know, fill a bug... but here is a super simple app that will demostrate that the navigation bar chnages from Dark scheme to light scheme when you tap back after it goes to the second view.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
NavigationLink {
Text("Tap back and notice the navigation title changes to black text instead of white")
.toolbarBackground(.visible, for: .navigationBar)
.toolbarBackground(Color.orange, for: .navigationBar)
.toolbarColorScheme(.dark, for: .navigationBar)
} label: {
VStack {
Text("First page is the sweetest")
}
.padding()
}
.navigationTitle("First Page")
.toolbarBackground(.visible, for: .navigationBar)
.toolbarBackground(Color.orange, for: .navigationBar)
.toolbarColorScheme(.dark, for: .navigationBar)
}
}
}
#Preview {
ContentView()
}
Everything was working fine until I updated MacOS.
Now, I'm getting the error:
'init(content:)' is only available in iOS 18.0 or newer
when simply using TabView & Tab in SwiftUI, which are definitely supported prior to iOS 18. Screenshot attached.
Can someone tell me what the heck is going on?
Hi
I am using PhotosPicker and SwiftData with iOS17.0.
I released my own app using codes of two above. No problem came up right until I upgraded my iphone to iOS 18.0 17th of September 24. A single post pokes the similar problem. SwiftData and PhotosPikcer. He or She said it was about SwiftData Model Insert something. But, I was able to use other methods that use SwiftData, so insert Model setup isn't my problem.
But when tapping a photo to get a photo from PhotosPicker makes the ui goes down, and navigate back. Weird. iIt doesnt crash but when I tap a photo, the debug message [ERROR] Could not create a bookmark: NSError: Cocoa 4097 "connection to service named com.apple.FileProvider" comes up and the view navigates back.
The selecting a photo itself doesnt include any SwiftData related methods, it only does loadTransferable thing and shows the photo on the screen.
I cannot understand it. it only happened when I upgraded to iOS 18.0. AND Then i debugged the prob with Xcode 16.0 nothing but the unexpected message appears and not many posts are up here or google. Can you help me?
Things I tried:
Check any use of the PhotosPickerItem anywhere else. -> No where.
Use try await loadTransferable
Changed the form of initiating PhotosPikcer View
Debugging every line -> Nothing appeared.
PhotosPicker(selection: $currentImage, matching: .images, photoLibrary: .shared()) {
Text("")
}
.frame(height: 360)
.photosPickerStyle(.inline)
.photosPickerAccessoryVisibility(.hidden, edges: .bottom)
.photosPickerDisabledCapabilities(.selectionActions)
.onChange(of: currentImage) { _, newImage in
// SomeLogic
}
.ignoresSafeArea(edges: .bottom)
.transition(.move(edge: .bottom).combined(with: .opacity))
Unable to compile app that imports Swift UI Charts SDK on Xcode Version 16.1 beta 2 (16B5014f) with error:
Failed to build module 'Charts'; this SDK is not supported by the compiler (the SDK is built with 'Apple Swift version 6.0 effective-5.10 (swiftlang-6.0.0.7.41 clang-1600.0.24.1)', while this compiler is 'Apple Swift version 6.0 effective-5.10 (swiftlang-6.0.0.9.11 clang-1600.0.26.2)'). Please select a toolchain which matches the SDK.
FB15161667
I have a colorSet which includes a "Any Appearance" color and a "Dark" color. I have a need to get the hex value of both.
I know how to add a .colorScheme(.dark) view modifier to cause the view to adapt to darkMode. That is not the issue. I want to display a swatch containing the darkMode color and I want to display the hex value under the swatch. No matter what I do, it always returns the hex value of the "Any Appearance" version of the color.
It seems that the solution might be to use Color.resolve(in:EnvironmentValues), but I do not see how to specify the needed EnvironmentValues
In iOS 18, textSelection(_:) not working in List. So, I can't copy text. Works on iOS 17 and earlier. Is this a bug and is there any solution?
// Not Work: iOS 18
struct ContentView: View {
var body: some View {
List {
Text("Hello World")
.textSelection(.enabled)
}
}
}
// Work: iOS 18 and earlier
struct ContentView: View {
var body: some View {
Text("Hello World")
.textSelection(.enabled)
}
}
I switched from using @Query to @ModelActor because of the following reasons:
Performance Issues: With @Query, my app became unresponsive with large datasets because data fetching occurred on the main thread.
Integration with CKSyncEngine: I needed to implement @ModelActor anyway to allow CKSyncEngine to add data to local persistent storage from the background.
In my current setup, the onAppear() method for my view calls the getItems() function on my model actor, which returns [ItemsDTO] and then View renders them.
However, I'm now facing a challenge in achieving the same automatic data refreshing and view updates that @Query provided. Here are a few potential solutions I'm considering:
Periodic Data Fetching: Fetch data at regular intervals to keep the view updated. But this seems expensive.
Local Write Monitoring: Monitor all local writes to automatically trigger updates when changes occur. But this is quite a lot of code I would have to write myself.
Switch to manual refresh: Users would have to manually trigger UI updates by pressing button.
Reintroduce @Query: Writes would happen from ModelActor, but reads would still happen from Main thread. But then again app would become unresponsive on reads.
If you have any additional ideas or best practices for maintaining reactivity with @ModelActor, I'd love to hear them!
I am working on an application that has some complex navigation needs, and I'm considering abandoning SwiftUI, at least in a few core areas of the app. I found SwiftUI intuitive and useful for simple things like:
Using a state to toggle the appearance or disappearance of an element
Using state to alter the look of UI elements
Watching the values of built-in interfaces like TextField or Slider
Controlling out-of-the-box UI elements like NavigationSplitView
But now I've got a UI that depends on a data model that can change at any time, and from that data I'll display lists of objects, and objects in detail, and all of this will be displayed according to a NavigationPath that depends on the data model's internal structure. This means that, for instance, I may be in the detail view of element X after having traveled to it from the detail view of element Y which was tapped in a list of XYZ, which was the result of tapping into part of the detail view of element W. This whole path could be invalidated by an update to the data model when it's received from the network. Furthermore, any element could have it's details changed, or be deleted, and I'd want the UI to reflect that right away if possible.
For the navigation work, I'm still optimistic that custom edits to a NavigationPath could be the way to go. However, for propagating data updates around my app, I know @State, @Bindable, etc are intended to handle this kind of thing, but when I'm try to send these bindings through the circuitous path of views I mentioned above, and I run into any unexpected hiccup, it feels like I'm at a disadvantage when debugging because I'm relying on opaque SwiftUI Magic to handle things under the hood in a way I don't really understand. I could put more effort into learning how this works, and potentially come up against some platform limitations, bugs, or other dead-ends, or I could just use Pub/Sub and a network of custom queues/pipes, and send updates around my app the old fashioned way, but using primitives whose functions are clear to me. I've been using SwiftUI for about a year and it still trips me up, and I have watched a few WWDC talks on the topic.
I'd appreciate any advice on this front from the frequenters of this forum. Thanks for reading my post.
struct ContentView: View {
var body: some View {
NavigationSplitView {
List {
Text("row 1")
Text("row 2")
Text("row 3")
}
.toolbar(content: {
ToolbarItem {
Button("aa", action: onToolbar)
}
})
} detail: {
HSplitView {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.toolbar(id: "toolbar", content: {
ToolbarItem(id: "toolbar-1") {
Button("bb", action: onToolbar)
}
})
.padding()
Text("right")
}
}.navigationTitle("")
}
func onToolbar() {}
}
Run & Crash
NSToolbar 0x6000005665b0 already contains an item with the identifier com.apple.SwiftUI.splitViewSeparator-0. Duplicate items of this type are not allowed.
Hi,
Is there anyway to auto format a text field to show mobiles numbers properly like a modifier or something ? and is there an API to check if the text is a valid mail address not just dummy text ?
--
Kind Regards
Hi,
The example that Apple shows in link below doesn't show how truncationMode works, because the text get truncated anyway when its length it more than frame height so what's the use of truncationMode ?
https://developer.apple.com/documentation/swiftui/view/truncationmode(_:)
--
Kind Regards
Using desaturated mode on an image in a widget will break any links or buttons that use the image as their 'label'.
Using the following will just open the app as if there was no link at all - therefore just using the fallback userActivity handler, or any .widgetURL() urls provided.
Link(destination: URL(string: "bug://never-works")!) {
Image("puppy")
.widgetAccentedRenderingMode(.desaturated)
}
The same goes for buttons:
Button(intent: MyDemoIntent()) {
Image("puppy")
.widgetAccentedRenderingMode(.desaturated)
}
I've tried hacky solutions like putting the link behind the image using a ZStack, and disabling hit testing on the image, but they don't work. Anything else to try?
Logged as Feedback #15152620.
When using a SwiftUI Text view with a relative date, with .minimumScaleFactor(), in a widget, the Text will always be shown at the minimum scale rather than the largest size possible. This started happening in iOS17, and is still the case in iOS18.
Therefore, if for example, you wanted to have a Text, showing a relative date in a countdown, with a "minimumScaleFactor" of 0.5, it will always show at 0.5 scale, no matter how much space there is available.
Text(.now, style: .relative)
.font(.system(size: 80, weight: .bold, design: .rounded))
.minimumScaleFactor(0.2)
^^ will always show at 0.2 scale (in a widget) even if there's space for much more.
This is only the case in widgets, not in the main app. Similarly, if you try to use "ViewThatFits" instead of "minimumScaleFactor", it will choose the smallest view, even if larger ones would fit.
Screenshot demonstrates the issue - all the countdown text views should be similarly large. This is not an issue with lack of vertical spacing causing the more flexible views to shrink - it behaves the same even if there's loads of vertical space too.
Maybe related, but trying to use ".fixedSize()" with a relative date Text view in a widget results in a completely blank widget.
Seems like a system bug rather than anything wrong in my code - I've logged it as Feedback (#15151577) with a demo project. Has anybody else come up against these issues - any solutions?