When using .searchable with placement: .toolbarPrincipal inside a NavigationStack, the search field is incorrectly placed at the bottom of the view instead of the principal position where ToolbarPlacement.principal normally resides. This is confirmed by testing: a ToolbarItem with placement: .principal containing Text("Title") gets pushed away when the .searchable modifier is added, yet the search field still appears at the bottom rather than taking over the principal location as documented.
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hi. The following code causes UI mismatch on iOS26. Keyboard with type decimalPad and appearance as dark is displayed as popUp with wrong colors. Before iOS26 keyboard was regular with correct color scheme. Please advice either how to make the scheme correct or force to display regular keyboard instead of popup.
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
textField.keyboardType = .decimalPad
textField.keyboardAppearance = .dark
view.backgroundColor = .darkGray
}
}
Hello everyone,
I’m running into an issue where a partial sheet repeatedly presents and dismisses in a loop.
Setup
The main screen is presented using fullScreenCover
From that screen, a button triggers a standard partial-height sheet
The sheet is presented using .sheet(item:)
Expected Behavior
Tapping the button should present the sheet once and allow it to be dismissed normally.
Actual Behavior
After the sheet is triggered, it continuously presents and dismisses.
What I’ve Verified
The bound item is not being reassigned in either the parent or the presented view
There is no .task, .onAppear, or .onChange that sets the item again
The loop appears to happen without any explicit state updates
Additional Context
I encountered a very similar issue when iOS 26.0 was first released
At that time, moving the .sheet modifier to a higher parent level resolved the issue
The problem has now returned on iOS 26.4 beta
I’m currently unable to reproduce this in a minimal sample project, which makes it unclear whether:
this is a framework regression, or
I’m missing a new presentation requirement
Environment
iOS: 26.4 beta
Xcode: 26.4 beta
I’ve attached a screen recording of the behavior.
Has anyone else experienced this with a fullScreenCover → sheet flow on iOS 26.4?
Any guidance or confirmation would be greatly appreciated.
Thank you!
Hello, I am attempting to implement a simple button that loads persistent data from a class (see below).
Button("Reload Data") {
while tableData2.isEmpty == false{
tableData2.remove(at: 0)
}
while tableView.isEmpty == false{
tableView.remove(at: 0)
}
//update
if csvData.isEmpty == false{
for superRow in csvData[0].tableData2{
tableData2.append(superRow)
}
for supperRow in csvData[0].tableView{
tableView.append(supperRow)
}
print("Item at 0: \(csvData[0].tableData2[[0][0]])")
print("\(tableData2[0][0])")
} else {
print("csvData is empty")
}
}
This button DOES work to appropriately print the data stored at the printed location once loaded in initially. The problem is that it doesn’t work across app restarts, which is the whole point of the button. Below I will include the rest of the relevant code with notes:
In contentView declaring the persistant variables:
Query private var csvData: [csvDataPersist]
Environment(\.modelContext) private var modelContext
The simple class of data I’m storing/pulling to/from:
@Model
class csvDataPersist{
var tableView: [[String]] = []
var tableData2: [[String]] = []
init(tableView: [[String]], tableData2: [[String]]) {
self.tableView = tableView
self.tableData2 = tableData2
}
}
In (appname)App: I tried both locations of the model container but it didn’t seem to matter
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: csvDataPersist.self)
}
//.modelContainer(for: csvDataPersist.self)
.modelContainer(sharedModelContainer)
}
How I’m attempting to save the data:
let newCSVDataPersist = csvDataPersist(tableView: tableView, tableData2: tableData2)
//modelContext.rollback()
//for superrow in csvData.count{
// csvData[superrow].tableData2.removeAll()
//}
//modelContext.rollback()
//csvData[0].tableData2.removeAll()
//csvData[0].tableView.removeAll()
if csvData.isEmpty == false {
print("not empty, deleting prev data")
modelContext.delete(csvData[0])
} else {
print("it empty, load data.")
}
modelContext.insert(newCSVDataPersist)
//try modelContext.save()
Note that I’ve tried just about every combination of enabling and disabling the commented out lines. This is the part of the code I am the least confident in, but after trying for hours to troubleshoot on my own I would appreciate any input from the community.
Something else that may be of note, in a previous attempt, upon a second startup, the terminal would print:
"coredata: error: error: persistent history (random number) has to be truncated due to the following entities being removed: ( csvdatapersist )"
Why is csvDataPersist getting removed? What is it getting removed by? Looking up this error was fruitless. Most sites instructed me to basically hard reset my simulators, clean the build, restart my computer, and try again. I've done all of these things about a hundred times at this point, with no results.
Any help would be much appreciated!
I'm building an app that heavily relies on EKEventStore for calendar and reminder integration. The API is simple - and limited.
Change notifications amount to "something changed, you'd better refetch everything you care about." There's no way to know whether the calendar was updated while your app was closed or backgrounded. EKEvents and EKReminders don't trigger SwiftUI view updates, so you end up shunting them into your own observable state and keeping the two in sync.
My app is fairly complex rendering-wise, and I lament being locked into treating EKEventStore as a first-class citizen of my view and data layer. It makes everything clunkier, essentially shuts the door on modern features like undo/redo, and makes integrating with other calendar providers that much harder.
I'm exploring a custom SwiftData DataStore ↔ EKEventStore sync engine, but this is no easy task. There are still many unknowns I'd need to spike out before I can even attempt a proper implementation.
Still, I'm curious - is this something being actively worked on behind the scenes? Will we see a more modern, observable, SwiftUI-native EventKit integration in the future?
iOS 26 – navigationItem.titleView shifted left when leftBarButtonItem is nil
Hi everyone,
I’m encountering a layout issue on iOS 26 related to navigationItem.titleView positioning.
What I’m Doing
I’m hiding the default back button and removing the left bar button item:
navigationItem.leftBarButtonItem = nil
navigationItem.hidesBackButton = true
navigationItem.setLeftBarButtonItems([], animated: true)
Then I create a custom titleView with a specific width calculated as:
Screen width minus the width of the two bar button items (left and right).
let titleView = UIView(frame: CGRect(origin: .zero, size: sizeOfTitleView))
let titleLabel = UILabel(frame: CGRect(origin: .zero, size: sizeOfTitleView))
Expected Behavior
On previous iOS versions, the titleView is perfectly centered in the navigation bar.
Actual Behavior (iOS 26)
On iOS 26, when leftBarButtonItem is nil, the titleView is pushed slightly to the left instead of being centered (see attached image).
Question
Has there been a change in UINavigationBar layout behavior in iOS 26?
What is the correct way to ensure the titleView remains perfectly centered when there is no leftBarButtonItem?
Any guidance would be appreciated. Thanks!
I'm trying to determine if this is "expected" swiftui behavior or an issue with SwiftUI/Data which needs a feedback request...
When a child view has a Query containing a filter predicate, the query is run with each and every edit of the parent view, even when the edit has no impact on the child view (e.g. bindings not changing).
In the example below, ContentView has the TextField name, and while data is being entered in it, causes the Query in AddTestStageView to be run with each character typed, e.g. 30 characters result in 30 query executions.
(Need "-com.apple.CoreData.SQLDebug 1" launch argument to see SQL output).
Removing the filter predicate from the query and filtering in ForEach prevents the issue.
In my actual use case, the query has a relatively small result set (<100 rows), but I can see this as a performance issue with the larger result sets.
xcode/ios: 26.2
Repro example code:
import SwiftUI
import SwiftData
// Repro to Query filter issue in child view running multiple time unexpectedly
// Need "-com.apple.CoreData.SQLDebug 1" launch argument set to see SQL console output.
@main
struct ReproViewQueryMultipleRunningsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(DataManager.shared.sharedModelContainer())
}
}
@Model
final class TestStageClass {
var id: UUID = UUID()
var name: String = ""
var isActive: Bool = true
var displayOrder: Int = 0
init(name: String, isActive: Bool, displayOrder: Int) {
self.name = name
self.isActive = isActive
self.displayOrder = displayOrder
}
}
struct ContentView: View {
@Environment(\.modelContext) var modelContext
@State private var name: String = ""
@State private var selectedTestStage: TestStageClass = DataManager.shared.getFirstTestStageClass()
var body: some View {
VStack (spacing: 20) {
TextField("Name", text: $name)
AddTestStageView(selectedTestStage: $selectedTestStage)
}
.frame(height: 200)
}
}
#Preview("Sample Data") {
ContentView()
.modelContainer(DataManager.shared.sharedModelContainer())
}
struct AddTestStageView: View {
@Environment(\.modelContext) var modelContext
@Binding var selectedTestStage: TestStageClass
// MARK: - ISSUE LOCATION
/// Using this Query with filter causes it to be run after each editing on parent view - such as each letter when editing a name.
@Query(filter: #Predicate<TestStageClass> { $0.isActive }) private var testStageClasses: [TestStageClass]
/// Using this query doesn't have the issue, then need filter in ForEach.
// @Query() private var testStageClasses: [TestStageClass]
var body: some View {
Picker("stage", selection: $selectedTestStage) { // filter and sort here does not affect issue with above Query predicate filter.
ForEach(testStageClasses.filter(\.isActive).sorted(by: { $0.displayOrder < $1.displayOrder } ), id: \.id) { stage in
Text("\(stage.name)")
.tag(stage)
}
}
}
}
class DataManager {
static let shared = DataManager()
private var modelContainer: ModelContainer? = nil
public func sharedModelContainer(inMemory: Bool = false) -> ModelContainer {
let schema = Schema([TestStageClass.self])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: inMemory)
do {
self.modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])
checkDataExists()
return self.modelContainer!
} catch {
fatalError("Could not create sharedModelContainer. Schema:\(schema.entities.map(\.name)), \((modelConfiguration.isStoredInMemoryOnly) ? "in memory only" : "in disk"):\n\(error.localizedDescription)")
}
}
private func checkDataExists() {
let mainContext = self.modelContainer!.mainContext
print("checkDataExists")
do {
let classData: [TestStageClass] = try mainContext.fetch(FetchDescriptor<TestStageClass>())
if classData.isEmpty {
mainContext.insert(TestStageClass(name: "Beginning", isActive: true, displayOrder: 0))
mainContext.insert(TestStageClass(name: "Second Middle", isActive: false, displayOrder: 2))
mainContext.insert(TestStageClass(name: "Middle", isActive: true, displayOrder: 1))
mainContext.insert(TestStageClass(name: "End", isActive: true, displayOrder: 3))
}
if mainContext.hasChanges {
try? mainContext.save()
print("Added Default Data for TestStageClass")
}
} catch {
fatalError("Failed to get item count for TestStageClass: \(error.localizedDescription)")
}
}
func getFirstTestStageClass() -> TestStageClass {
let mainContext = self.modelContainer!.mainContext
var tmp: TestStageClass?
do {
let classData: [TestStageClass] = try mainContext.fetch(FetchDescriptor<TestStageClass>())
tmp = classData.sorted(by: {$0.displayOrder < $1.displayOrder }).first
} catch {
fatalError("getFirstTestStageClass: \(error.localizedDescription)")
}
return tmp!
}
}
Thanks,
Steve
Hello
Using a MacBook Pro Intel with macOS 12.7.6 Monterey, I test in Objective-C an event for the option key but it is not working
- (void)keyDown:(NSEvent *)event {
printf("%s %p\n", __FUNCTION__, self);
BOOL altFlag = [event modifierFlags] & NSEventModifierFlagOption;
if (altFlag) {
// UpdateClass
printf("option pressed\n");
} else {
printf("option not pressed\n");
}
}
The same in Swift works fine
override func keyDown(with event: NSEvent) {
if event.modifierFlags.contains(.option) {
print("option pressed")
} else {
print("option NOT pressed")
}
}
The Obj-C code works fine on a MacBook Air Tahoe 26.3
Any idea why it does not work on the macOS 12.7.6 Intel?
Many Thanks
Jean
When using the .glassEffect modifier on a button in swiftui combined with the .interactive() modifier, the button continues to show the interactive animation even when it’s covered by another element.
Example:
ZStack {
Button {
print("Button overlayed by ZStack") // Does not trigger, but interactive animation still plays
} label: {
image
}
.glassEffect(.regular.interactive())
Rectangle().fill(.black.opacity(0.7))
}
This occurs with overlays, ZStacks, and even if the overlay is a button.
Example below: EDIT: It seems like rocketsim's gif recording doesnt show the bug for some reason... really strange... Edit 2: reuploaded gif, recorded as mp4 and converted to gif seems to have worked...
Feedback ID: FB22054300
I've attached this sample app to my feedback ticket to help with debugging the issue. It doesn't look like I can share it in this post though.
In SwiftUI, when using NavigationStack with a path binding containing multiple instances of the same (or many with navigationPath()) model type (since model type are class type, this issue might occur on instances of class type too), any NavigationLink in a detail view that leads to a value already present anywhere in the navigation stack (which is in the path binding) will appear incorrectly highlighted upon the view's initial appearance. This bug seems manifests specifically when the links are contained within a List. The highlighting is inconsistent - only the earliest appended value in path has link in each section displays as pressed, while links to other value appear normal.
Below is a simple code to reproduce the bug.
import SwiftUI
import SwiftData
// Simple model
@available(iOS 17, *)
@Model
class Item {
var id = UUID()
var name: String
var relatedItems: [Item]
init(name: String = "", relatedItems: [Item] = []) {
self.name = name
self.relatedItems = relatedItems
}
}
// MARK: - Bug Reproducer
@available(iOS 17, *)
struct BugReproducerView: View {
@State private var path: [Item] = []
let items: [Item]
init() {
let item1 = Item(name: "Item 1", relatedItems: [])
let item2 = Item(name: "Item 2", relatedItems: [item1])
item1.relatedItems = [item2]
self.items = [item1, item2]
}
var body: some View {
NavigationStack(path: $path) {
List(items) { item in
NavigationLink(item.name, value: item)
}
.navigationTitle("Items")
.navigationDestination(for: Item.self) { item in
DetailView(item: item)
}
}
}
}
// MARK: - Detail View with Bug
@available(iOS 17, *)
struct DetailView: View {
let item: Item
var body: some View {
List {
Section("Info") {
Text("Selected: \(item.name)")
}
if !item.relatedItems.isEmpty {
Section("Related") {
ForEach(item.relatedItems) { related in
NavigationLink(related.name, value: related)
}
}
}
}
.navigationTitle(item.name)
}
}
#Preview {
if #available(iOS 17, *) {
BugReproducerView()
} else {
}
}
We are facing some weird issue in the UILabel initialisation. Also it is occurring sometimes.
class TextLabel: ConfigurableView<TextLabel.Config> {
struct Config {
var text: String = .empty
var font: UIFont?
var textColor: UIColor?
var maxLines: Int = 0
var attributedText: NSAttributedString?
var textAlignment: NSTextAlignment = .natural
var truncateWithMore: Bool = false
var onTapShowMore: (() -> Void)?
var onTap: (() -> Void)?
var accessibilityIdentifier: String?
}
private lazy var label: UILabel = {
let label = UILabel() **//##### Crash is occurring in this line.**
label.translatesAutoresizingMaskIntoConstraints = false
label.adjustsFontForContentSizeCategory = true
return label
}()
private lazy var tapGesture = UITapGestureRecognizer(target: self, action: #selector(onTap))
private var isTruncated = false
override func setUp() {
addSubview(label)
label.equalsContainer()
}
override func layoutSubviews() {
super.layoutSubviews()
updateContent()
}
override func setConfig(_ config: Config) {
super.setConfig(config)
updateContent()
}
@objc func onTap() {
if isTruncated {
config?.onTapShowMore?()
} else {
config?.onTap?()
}
}
func updateContent() {
guard let config = config else { return }
label.numberOfLines = config.maxLines
label.text = config.text
}
}
You can find my configurable view below.
import UIKit
class ConfigurableView<T>: UIControl {
private(set) var config: T?
init(_ config: T) {
super.init(frame: .zero)
setUp()
setConfig(config)
}
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setUp() {
}
func setConfig(_ config: T) {
self.config = config
}
}
This crash is occurring randomly. Sometimes we could reproduce it in the app updates.
Topic:
UI Frameworks
SubTopic:
UIKit
Description
I am observing a critical issue when saving burst photos using the Photos Framework. If a burst photo with the same burstIdentifier already exists in the "Recently Deleted" album, any new assets saved via PHAssetCreationRequest are automatically merged into that deleted entry instead of appearing in the main Library or "All Photos."
Environment
Framework: Photos Framework (iOS)
API: [[PHPhotoLibrary sharedPhotoLibrary] performChanges:...]
Code Snippet
The following logic is used to save the burst assets:
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
// 'paths' is a custom object providing the creation request
PHAssetCreationRequest *assetCreationRqst = [paths assetCreationRqst];
assetCreationRqst.favorite = [FavorManager.shared isSetDownloadedAssetFavorite:self.curItem];
PHObjectPlaceholder *placeHolder = assetCreationRqst.placeholderForCreatedAsset;
localIdentifier = placeHolder.localIdentifier;
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
// The handler returns success, but the asset is invisible to the user
[weakSelf handleDownloadSuccess:localIdentifier];
}
// ... cleanup and completion ...
}];
Steps to Reproduce
Save a burst photo to the iPhone's built-in Photos app.
Manually delete that burst photo so it moves to the "Recently Deleted" album.
Execute the code above to save the same burst photo (or a new set containing the same burstIdentifier in its metadata).
Check the main Photo Library / "All Photos" view.
Observed Result
The completionHandler returns success = YES, and a localIdentifier is generated.
The photo does not appear in the main Library or "All Photos."
The newly saved photo is silently merged into the existing burst set located inside the "Recently Deleted" folder.
The user cannot see the new photo unless they manually "Restore" the deleted items from the album.
Expected Behavior
PHAssetCreationRequest should always result in a visible asset in the user's Library. Even if a matching burstIdentifier exists in "Recently Deleted," the system should treat the new request as a new independent asset or provide an error, rather than hiding it within a deleted collection.
For the CountdownDuration initializer, since passing nil to both parameters of public init(preAlert: TimeInterval?, postAlert: TimeInterval?) is not considered valid, shouldn't the function signature be changed to be two separate inits, instead of a runtime error.
EX:
public init(preAlert: TimeInterval, postAlert: TimeInterval?)
public init(preAlert: TimeInterval?, postAlert: TimeInterval)
Topic:
UI Frameworks
SubTopic:
General
In this Mac App, I have an IBOutlet (which is defined as instance of a subclass of NSView).
When I connect the IBOutlet to the code, referencing as file's owner, it works OK.
But if I reference to the class, it crashes, when I access a specific IBOutlet (but other IBOutlets are accessed just before it without crashing)..
The IBOutlet turnPageControl is defined as instance of subclass of NSView.
Note: I have implemented several init methods:
override init(window: NSWindow!) { }
required init?(coder: (NSCoder?)) { } // Yes, (NSCoder?)
convenience init(parameters) {
// loading from nib
}
override func windowDidLoad() {
super.windowDidLoad()
// Access turnpageControl
I get those calls before crash:
init(window:)
init(parameters:)
init(window:)
windowDidLoad() -> crash inside on accessing the IBOutlet
for turnPageControl.isHidden = true
Is there any reason to this ?
1ada58e6-51b3-4cc5-98a3-31c8d1597de5.crash
We are experiencing a segmentation fault crash when running our tests on AWS Device Farm. This crash only happens on iOS 18 and does not happen on iOS 26 also running on device farm.
We have not been able to replicate this crash locally and we have not seen this in any of our production app usage.
It appears there is some memory corruption going on and the trace always seems to crash inside Apple's UIKit code with -[UIImageSymbolConfiguration _initWithTraitCollection:].
I also see the following in the logs from CI:
[TraitCollection] Class CKBrowserSwitcherViewController overrides the -traitCollection getter, which is not supported. If you're trying to override traits, you must use the appropriate API.
We are not overriding traitCollection getter anywhere in our code and we have no usage of CKBrowserSwitcherViewController either. This crash happens when trying to go through the login flow to our app when KIF hits the login button.
I have tried debugging with Zombies and the memory graph debugger but nothing is sticking out as to what would be causing this issue. When running locally with Zombies I do not get any memory warnings going through our login flow.
Could this be a bug inside of UIKit on iOS18 which is getting exposed due to timing on AWS? Any help with next debugging steps would be appreciated.
Topic:
UI Frameworks
SubTopic:
UIKit
Environment:
Xcode 26.2
Simulator: 26.0 / iPhone 17
Summary:
Assigning a specific Unicode string to a UILabel (or any UITextView / text component backed by CoreText) causes an immediate crash. The string contains a visible base character followed by a zero-width non-joiner and two combining marks.
let label = UILabel()
label.text = "\u{274D}\u{200C}\u{1CD7}\u{20DB}"
// ^ Crash in CoreText during text layout
Crash stack trace:
The crash occurs inside CoreText's glyph layout/shaping pipeline. The combining marks U+1CD7 and U+20DB appear to stack on the ZWNJ (which has no visible glyph), causing CoreText to fail during run shaping or bounding box calculation.
Questions:
Is this a known CoreText regression in the iOS 26.0 simulator?
Is there a recommended fix or a more targeted workaround beyond stripping zero-width Unicode characters?
Will this be addressed in an upcoming update
Topic:
UI Frameworks
SubTopic:
General
Hi,
I have two views in my view hierarchy searchButtonView and searchBarView. I am trying to fade out the searchButtonView while animating the change in the frame of searchBarView simultaneously within a UIView.animate block. However, when I run the app, the frame of searchBarView resizes correctly while the alpha of searchButtonView does not animate to 0 as expected.
How can I fix this so that both view animate simultaneously?
Please see my code below.
Thank you
class MovieTitlesViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
var searchButtonView: UIView!
var searchBarView: UIView!
override func viewDidLayoutSubviews() {
createSearchButtonView()
createSearchBarView()
}
func createSearchButtonView() {
searchButtonView = UIView(frame: CGRect(x: 23, y: view.safeAreaInsets.top, width: 48, height: 48))
let searchImageView = UIImageView(image: UIImage(named: "Search Icon")!)
searchImageView.frame = CGRect(x: searchButtonView.frame.width / 2 - 16,
y: searchButtonView.frame.height / 2 - 16,
width: 32,
height: 32)
searchButtonView.addSubview(searchImageView)
searchButtonView.backgroundColor = .blue
searchButtonView.layer.cornerRadius = 24
searchButtonView.layer.borderColor = UIColor.gray.cgColor
searchButtonView.layer.borderWidth = 0.5
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tappedSearchView))
tapGesture.numberOfTapsRequired = 1
searchButtonView.addGestureRecognizer(tapGesture)
searchButtonView.isUserInteractionEnabled = true
view.addSubview(searchButtonView)
}
func createSearchBarView() {
searchBarView = UIView(frame: CGRect(x: 23,
y: view.safeAreaInsets.top,
width: 0,
height: 48))
searchBarView.backgroundColor = .red
// searchBarView.backgroundColor = UIColor(red: 217/255, green: 217/255, blue: 217/255, alpha: 1.0)
searchBarView.layer.cornerRadius = 24
searchBarView.layer.borderColor = UIColor.gray.cgColor
searchBarView.layer.borderWidth = 0.5
view.addSubview(searchBarView)
}
func animateExpandSearchView() {
UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut) {
self.searchButtonView.alpha = 0.0
self.searchBarView.frame = CGRect(x: 23, y: self.view.safeAreaInsets.top, width: UIScreen.main.bounds.width - 46, height: 48)
}
}
@objc func tappedSearchView() {
print("tapped search view")
animateExpandSearchView()
}
}
Topic:
UI Frameworks
SubTopic:
UIKit
FeedBack Id: FB22031397 (Demo proj Attached to Feedback)
Description:
When a TabView using .page tabViewStyle is placed inside a sheet configured with multiple presentationDetents, dragging the sheet handle to resize between detents causes the TabView to re-render all its pages on every frame of the drag gesture. This results in visible content vibration, scroll position jumping, and tab content flashing during the drag. The issue is fully reproducible with the attached minimal demo project.
Steps to Reproduce:
Run the attached TabViewSheetVibrationDemo.swift on any iOS device or simulator
Tap "Open Sheet" on the main screen
Swipe left to any tab
Scroll down inside the tab so content is not at the top
Grab the sheet drag indicator at the top and slowly drag upward or downward to resize between medium and large detent
Observe the tab content while dragging
Expected Results:
The TabView page content should remain completely stable during sheet resize. Scroll positions should be preserved and no re-rendering should occur because the underlying data has not changed. The sheet should resize smoothly while tab content stays still.
Actual Results:
The TabView re-renders all pages on every frame of the drag gesture. This causes:
Visible content vibration and jitter while dragging the sheet handle
Scroll position jumping back toward the top mid-drag
Tab content flashing as pages are recreated
The problem is proportional to drag speed — slower drags show a stuttering effect, faster drags cause a full content flash
Configuration:
All Xcode including beta
iOS 26 (also reproduced on iOS 16, iOS 17 and iOS 18)
Reproducible on both Simulator and real device
Affects iPhone and iPad
There appears to be a bug in Link with IPv4 addresses with padding in the second octet, on macOS and iOS both.
struct LinkViewBug: View {
let works = URL(string: "http://172.16.1.1")!
let alsoWorks = URL(string: "http://172.16.001.001")!
let doesntWork = URL(string: "http://172.016.001.001")!
let alsoDoesntWork = URL(string: "http://172.016.1.1")!
var body: some View {
// destination -> http://172.16.1.1
Link(works.formatted(), destination: works)
Link(alsoWorks.formatted(), destination: alsoWorks)
// destination -> http://172.14.1.1 ?
Link(doesntWork.formatted(), destination: doesntWork)
Link(alsoDoesntWork.formatted(), destination: alsoDoesntWork)
}
}
In macOS 26, there is a new property on NSControl called .borderShape.
The WWDC 2025-310 video says it can be used to "Override preferred shape of control to suit your design." and that it's available on NSButton, NSPopUpButton and NSSegmentedControl.
Is there an equivalent to that property for SwiftUI? For example, given the following SwiftUI code:
Button("Eject") {
}
.borderShape(...) <-- ?
How can I apply a .borderShape that would match those on controls created in AppKit?
I'm aware that SwiftUI offers a plethora of ways to custom design a button such that it can have rounded corners, but I'm interested in this particular property so that SwiftUI buttons and AppKit buttons in the same app have the same look-and-feel.