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.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

iPhone Duo: navigation bar item briefly moves to vertical bar during fullScreen dismissal despite .disabled
On the folded iPhone Duo display, a navigation bar item briefly moves into the vertical bar during dismissal of a full-screen modal, then jumps back to the top. Both navigation controllers consistently return .disabled from preferredVerticalBarBehavior, with childForPreferredVerticalBarBehavior returning nil. Environment Xcode 27.1 RC (27A9275), iOS 27.1 SDK, iPhone Duo simulator, folded outer display in portrait. Steps to reproduce Run the single-file UIKit example below in a scene-based app with a generated launch screen and no main storyboard. Tap the gear button on the Home screen to present Settings using .fullScreen. Tap the close button on Settings. Watch the Home screen's gear button during the dismissal animation. Expected The gear button stays in the top horizontal navigation bar throughout the transition, because the vertical bar preference is .disabled on both navigation controllers. Actual For part of the dismissal, the gear button appears below the status icons in the right-hand vertical bar region. It then jumps back to the top horizontal bar. The underlying tab bar also temporarily moves from the bottom to the right before returning. This reproduces with an otherwise empty view, standard UIKit containers, and the default bar appearance. No app code changes safeAreaInsets, bar frames, or animation timing. During the presentation/dismissal cycle, the Home view's logged right safe-area inset changes from 0 to 88 points and back to 0. In our app, content constrained to the safe area visibly narrows during the same transient change. In separate comparisons, returning .disabled from the root tab controller and content controllers, or requesting setNeedsUpdateOfVerticalBarConfiguration in appearance callbacks, did not eliminate the issue. Changing the modal to .overFullScreen avoided it in the tested simulator, but changes the underlying view controller lifecycle. The example below intentionally keeps .fullScreen to reproduce the problem. Is this expected behavior, or a known UIKit issue? Is there a supported way to keep .disabled effective throughout a fullScreen presentation/dismissal? Has this been addressed in a newer SDK/runtime? I have not tested iOS 27.2 or a physical Duo device. Minimal reproduction (one Swift file): import UIKit @main final class DemoAppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { let configuration = UISceneConfiguration(name: "Demo", sessionRole: session.role) configuration.delegateClass = DemoSceneDelegate.self return configuration } } final class DemoSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let home = DemoController() home.title = "首页" let navigation = DemoNavigationController(rootViewController: home) navigation.tabBarItem = UITabBarItem(title: "首页", image: UIImage(systemName: "house"), selectedImage: nil) let tabs = UITabBarController() if #available(iOS 18.0, *) { tabs.mode = .tabBar } tabs.viewControllers = [navigation] let window = UIWindow(windowScene: scene) window.rootViewController = tabs self.window = window window.makeKeyAndVisible() } } final class DemoNavigationController: UINavigationController { // 与音剪一致:导航容器固定横向栏,不转发给子页面。 @available(iOS 27.1, *) override var preferredVerticalBarBehavior: UIVerticalBarBehavior { .disabled } @available(iOS 27.1, *) override var childForPreferredVerticalBarBehavior: UIViewController? { nil } } final class DemoController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground if title == "设置" { navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction { [weak self] _ in self?.dismiss(animated: true) }) } else { navigationItem.rightBarButtonItem = UIBarButtonItem( image: UIImage(systemName: "gearshape"), primaryAction: UIAction { [weak self] _ in let settings = DemoController() settings.title = "设置" let navigation = DemoNavigationController(rootViewController: settings) navigation.modalPresentationStyle = .fullScreen self?.present(navigation, animated: true) }) } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() print("[DuoDemo] \(title ?? "") safe=\(view.safeAreaInsets) nav=\(navigationController?.navigationBar.frame ?? .zero) tab=\(tabBarController?.tabBar.frame ?? .zero)") } }
0
2
501
3w
UIScreen.screens.count differs on iPhone Duo sims depending on if app is IOS 26 SDK, or iOS 27 SDK
Hi there, My app uses UIScreen.screens.count (deprecated) to predict whether mirroring is happening on older iOS devices I noticed that the number of screens is different between iOS 26 SDK apps, and iOS 27 SDK apps. Can I expect that iOS 26 SDK apps will continue to return 1 screen like below for the iPhone Duo release?. I assume it's like this is to maximise compatibility. App built with SDK 26 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 1 App built with SDK 27 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 2 Thanks for the help! Sam
Topic: UI Frameworks SubTopic: UIKit Tags:
4
0
388
3w
iPhone Duo - globe button appeared in RC 1 - intended change or bug?
In Xcode 27.1 RC 1 the native keyboard layout has been changed and now it shows the globe button. It looks like a bug but I'm not sure. Is the keyboard going to display the globe button in the final release? On top of that, the keyboard extension tells not to show its own globe button, so it's another point confirming that this is RC 1 regression bug. Xcode 27.1 Beta 1: Xcode 27.1 RC 1:
3
0
1.1k
3w
SwiftData Sectioning iOS 27
I try Apple: Adopting SwiftData for a Core Data App . But I have error " 'init(filter:sort:transaction:sectionBy:)' requires the types '[Trip]' and 'SectionedResults<Array.Element, String>' (aka 'SectionedResults<Trip, String>') be equivalent" at code line Query(filter: filter, sort: [sortDescriptor], sectionBy: sectionBy)
Topic: UI Frameworks SubTopic: SwiftUI
1
0
383
3w
LiveCommunicationKit: Handle.displayName is never shown — the call UI and Recents show Handle.value
On iOS [27.x (build)], LiveCommunicationKit shows Handle.value on every system surface and ignores Handle.displayName. That forces a choice that CallKit doesn't: Put a stable account id in value (as WWDC26 session 226 recommends, so Recents redial can identify the person), and the raw id appears on the incoming call screen, the banner and in Recents. Put the person's name in value so the UI reads correctly, and a redial from Recents hands back only the name, which can't reliably identify anyone. Minimal reproduction let configuration = ConversationManager.Configuration( ringtoneName: nil, iconTemplateImageData: nil, maximumConversationGroups: 1, maximumConversationsPerConversationGroup: 1, includesConversationInRecents: true, supportsVideo: false, supportedHandleTypes: [.generic, .phoneNumber, .emailAddress] ) let manager = ConversationManager(configuration: configuration) let remote = Handle(type: .generic, value: "u-1234", displayName: "Jane Appleseed") try await manager.reportNewIncomingConversation( uuid: UUID(), update: Conversation.Update(members: [remote], capabilities: []) ) Expected: the incoming call UI and the Recents row show "Jane Appleseed". Session 226 says displayName is "what the system shows when it can't match the handle to a contact". Tapping the Recents row delivers an INStartCallIntent whose contact personHandle.value is u-1234. Actual: the full-screen ring, the foreground banner and the Recents row all show u-1234. Tapping the row does deliver INStartCallIntent with personHandle.value == "u-1234", so redial works, but the user never sees the name. What we tried, all with the same result (the value is shown): Handle.Kind set to .generic, .phoneNumber or .emailAddress, with every kind listed in supportedHandleTypes Conversation.Update(localMember:) set to the local user's handle activeRemoteMembers set to the remote handle, and localMember plus activeRemoteMembers together Donating an INInteraction (an INStartCallIntent whose INPerson has personHandle set to the id, displayName set to the name and customIdentifier set to the id) when the conversation ends. The donation succeeds, but the Recents row and the redial payload don't change. CallKit comparison, same device: CXCallUpdate.remoteHandle = CXHandle(type: .generic, value: "u-1234") with localizedCallerName = "Jane Appleseed" shows the name on the ring and in Recents. A redial from Recents delivers personHandle.value == "u-1234". That's the behaviour we expected from LiveCommunicationKit. Questions: Is Handle.displayName meant to be shown when the handle doesn't match a contact? If so, is there a configuration step we're missing? If this is a bug, is there a supported way with LiveCommunicationKit to show a name while keeping a stable identifier for Recents redial? Filed as FB24933340. Device: iPhone 15 pro, iOS [27.0.1].
4
0
503
4w
WARNING: Application performed a reentrant operation in its NSTableView delegate. This warning will become an assert in the future.
Can anyone help to understand what is causing this warning message on this SampleCode. it happens when data in table gets updated it happens when I have lot of items in table and search for lets say # 6543 and then clear the search. "WARNING: Application performed a reentrant operation in its NSTableView delegate. This warning will become an assert in the future." If there are just few items in table, the warning is not there. And it started when updated to Xcode Version 14 and upward import SwiftUI import Foundation @main struct TestProjectSWIFTApp: App {     @StateObject var mydata: MyData = MyData()     var body: some Scene {         WindowGroup {             ContentView()                 .environmentObject(mydata)         }              } } struct ContentView: View {     @EnvironmentObject var mydata: MyData     var body: some View {         NavigationView{             NavigationLink("TABLE",  destination: MyTable())                      }     } } struct User: Identifiable {     let id: UUID = UUID()     var name: String     var score: Int } struct MyTable: View {     @EnvironmentObject var mydata: MyData     @State private var sortOrder = [KeyPathComparator(\User.name)]     @State var searchText: String = ""     var searchResults : [User] {         if searchText.isEmpty {             return mydata.alldata         } else {             return mydata.alldata.filter{$0.name.localizedCaseInsensitiveContains(searchText)}         }     }          var body: some View {                  Button("Generate new data", action: {             mydata.updateTable()         })                  Table(searchResults, sortOrder: $sortOrder) {             TableColumn("Score"){                 Text("\(Double($0.score))")             }             TableColumn("user", value: \.name)         }         .onChange(of: sortOrder) {             mydata.alldata.sort(using: $0)         }         .searchable(text: $searchText)     } } @MainActor class MyData : ObservableObject{     @Published var alldata: [User] = []               init(){         self.setData()     }          func setData(){         alldata = [             User(name: "User 1", score: 95),             User(name: "User 2", score: 80),             User(name: "User 3", score: 85)         ]     }          func updateTable(){         var newallData: [User] = []         var x = 0         while x < 10000{             newallData.append(User(name: "User #\(x)", score:  Int.random(in: 10..<999999)))                          x = x + 1         }         alldata = newallData     }      }
18
5
5.2k
4w
Live Activities: no minute-granularity self-updating countdown text; custom DiscreteFormatStyle types fail to decode in the system renderer
Summary There is no supported way for a Live Activity to display a self-updating countdown at minute granularity in the form transit riders expect — a bare "7 min" that ticks to "6 min" — even though Apple's own apps (Timer in the Dynamic Island, Maps ETA) display exactly this form. The API that should make this possible — Text(_ input: TimeDataSource<Date>, format:) with a custom DiscreteFormatStyle (added in iOS 18) — compiles and archives, but the rendered activity fails at decode time in the system renderer, so every region of the Live Activity displays grey placeholder boxes. What I'm building An NYC subway departures app. The app's design language everywhere (in-app, home screen widgets via baked timeline entries) is "7 min" / "Now". Real-world fidelity is minute-level: riders don't think in mm:ss. The Live Activity is the only surface that cannot match this design, because it can only use self-updating text between content updates, and none of the built-in live formats produce it. Built-in options and why each falls short Text(timerInterval:countsDown:) — mm:ss only; no minute-granularity mode (this is FB23091094). Also reserves maximum width (FB23091111). Text(date, style: .relative) — always appends a second unit ("7 min, 30 sec") and counts up ambiguously (unsigned) after the date passes. .reference(to:allowedFields:maxFieldCount:) (iOS 18) — closest usable option, but only spelled-out wide units with a mandatory preposition: "in 7 minutes". No abbreviated/narrow width option exists on SystemFormatStyle.DateReference. .offset(to:) (iOS 18) — measures time since the anchor, so an upcoming departure renders as a negative value ("−7 minutes"); inverted for countdown use, and also wide-units only. The bug: custom DiscreteFormatStyle fails to decode in the renderer A custom format style solves this completely — mine rendered exact "7 min"/"Now" strings and, by holding the full departure list, even advanced to the next train the moment one departed, all without waking the app: @available(iOS 18.0, *) struct TrainCountdownFormat: DiscreteFormatStyle { var departures: [Date] var rank: Int // 0 = closest upcoming train var fullText: Bool // "7 min" vs "7m" func format(_ now: Date) -> String { let upcoming = departures.filter { $0 > now }.sorted() guard rank < upcoming.count else { return "—" } let totalSeconds = Int(upcoming[rank].timeIntervalSince(now)) if totalSeconds < 60 { return "Now" } let minutes = totalSeconds / 60 return fullText ? "\(minutes) min" : "\(minutes)m" } func discreteInput(after input: Date) -> Date? { departures.compactMap { departure -> Date? in let seconds = departure.timeIntervalSince(input) guard seconds > 0 else { return nil } let intoMinute = seconds.truncatingRemainder(dividingBy: 60) return input.addingTimeInterval(intoMinute > 0 ? intoMinute : 60) }.min() } func discreteInput(before input: Date) -> Date? { departures.compactMap { departure -> Date? in let seconds = departure.timeIntervalSince(input) guard seconds > 0 else { return departure < input ? departure : departure.addingTimeInterval(-60) } let intoMinute = seconds.truncatingRemainder(dividingBy: 60) return input.addingTimeInterval(intoMinute - 60) }.max() } } // In the ActivityConfiguration views: Text(.currentDate, format: TrainCountdownFormat(departures: dates, rank: 0, fullText: true)) This compiles and the activity is created, but every presentation (compact trailing, expanded, lock screen) renders as grey placeholder boxes. The console shows the archive being rejected at decode time in the renderer process: WidgetRenderer_Activities: (WidgetRenderer) [com.apple.chrono:activityRendererClient-verbose] Failed to return view entry from archive for view model with tag dynamicIsland-compactTrailing with error: SwiftUI.AnyCodable<...SafelyCodableRequirement>...Errors.noType(mangledName: "7SwiftUI18TimeDataFormattingO10ResolvableVy_AA0cD6SourceVAAE11DateStorageOy10Foundation0H0V_G 27NowDepartingWidgetExtension10$1030be9a0yXZ20TrainCountdownFormatV G") i.e. the archived TimeDataFormatting.Resolvable wrapper references a type defined in the app's widget extension, which the system renderer cannot look up. Nothing in the DiscreteFormatStyle or Text(_:format:) documentation states that only system-defined format styles are renderable in Live Activities, and there is no compile-time or runtime diagnostic surfaced to the developer — the activity just renders blank. Requests (either would unblock this) Support custom DiscreteFormatStyle types in Live Activity rendering (e.g. by evaluating the format in the extension's process when pre-rendering discrete frames), or at minimum document the limitation and fail loudly instead of rendering placeholder boxes. Add minute-granularity and unit-width options to the built-in live formats: a showsSeconds/fields option on Text(timerInterval:) (FB23091094), and/or a units-width option (abbreviated/narrow) plus a "bare duration, no preposition, countdown sign convention" variant on SystemFormatStyle.DateReference / DateOffset. Steps to reproduce Create a Live Activity whose views use Text(.currentDate, format:) with any custom DiscreteFormatStyle (sample above). Start the activity; background the app. Observe the Dynamic Island and lock screen render grey placeholder boxes for every region, and WidgetRenderer_Activities logs Errors.noType for each view model tag. Expected: the custom format renders and updates at the boundaries reported by discreteInput(before:/after:), as it does for the system styles. Actual: decode failure in the renderer; entire activity renders as placeholders. Environment Xcode 27.0 (27A266a) iOS 27.0 simulator, iPhone 18 Pro (also applies to iOS 18+ per API availability) Widget extension deployment target: iOS 17.6 Related reports: FB23091094, FB23091111, forum thread https://developer.apple.com/forums/thread/834337
1
0
130
4w
iOS 27: ScrollViewProxy.scrollTo no longer reaches unrealized LazyVStack rows; how to preserve position when prepending?
I have a chat screen built with ScrollView { LazyVStack } and ScrollViewReader. Two things that worked through iOS 26 stopped working on iOS 27 (Xcode 27, iOS 27.0 simulator and device; unchanged code still works on the iOS 26.x simulator): Open at the newest message. On appear I call proxy.scrollTo(lastId, anchor: .bottom). On iOS 27 the list stops two or three rows above the bottom when the rows have variable heights (text bubbles mixed with 200pt images). Load older messages at the top without the list jumping. When the user reaches the top, I prepend 25 older messages and call proxy.scrollTo(previousTopId, anchor: .top) so the row they were reading stays put. On iOS 27 the call does nothing: the list stays at the top of the newly inserted page (offset stays at 0), which immediately re-triggers the load. Re-issuing scrollTo on every layout change for a short window (which is what made this reliable on iOS 26) has no effect on iOS 27. Minimal reproduction import SwiftUI struct Message: Identifiable, Hashable { let id: Int let height: CGFloat // simulates text vs. image bubbles } @MainActor final class ChatModel: ObservableObject { @Published var messages: [Message] = [] @Published var previousTopId: Int? // set when a page is prepended private var nextOldId = 1_000 init() { messages = (0..<25).map { Message(id: nextOldId - $0, height: Self.randomHeight()) }.reversed() nextOldId -= 25 } func loadOlder() { let top = messages.first!.id let page = (0..<25).map { Message(id: nextOldId - $0, height: Self.randomHeight()) }.reversed() nextOldId -= 25 messages.insert(contentsOf: page, at: 0) previousTopId = top // "keep this row at the top" } static func randomHeight() -> CGFloat { [44, 60, 90, 200, 260].randomElement()! } } struct ChatView: View { @StateObject private var model = ChatModel() var body: some View { ScrollViewReader { proxy in ScrollView { LazyVStack(spacing: 8) { // top sentinel: load older when it becomes visible Color.clear.frame(height: 1) .onAppear { model.loadOlder() } ForEach(model.messages) { m in RoundedRectangle(cornerRadius: 12) .fill(m.height >= 200 ? .orange.opacity(0.4) : .blue.opacity(0.3)) .frame(height: m.height) .overlay(Text("\(m.id)")) .padding(.horizontal) .id(m.id) } } } .onAppear { // (1) open at the newest message DispatchQueue.main.async { proxy.scrollTo(model.messages.last!.id, anchor: .bottom) } } .onChange(of: model.previousTopId) { _, id in // (2) restore the row that was at the top before the prepend guard let id else { return } DispatchQueue.main.async { var t = Transaction(); t.disablesAnimations = true withTransaction(t) { proxy.scrollTo(id, anchor: .top) } } } } } } Observed (1) Open at the newest message, scrollTo(lastId, anchor: .bottom) iOS 26.x: lands on the last row. iOS 27.0: stops 2–3 rows above the bottom. (2) Prepend 25 rows, then scrollTo(previousTopId, anchor: .top) iOS 26.x: the previous top row is at the top of the viewport. iOS 27.0: the offset stays at 0 and the new page's first row is at the top. What I have tried on iOS 27 Re-issuing scrollTo for 0.5s on every content-height or offset change (via GeometryReader preferences). No effect; the target row is not realized, and the visible rows are kept stable instead. .defaultScrollAnchor(.bottom) and .defaultScrollAnchor(.bottom, for: .sizeChanges): fixes the initial open, but the stored anchor is re-applied once on the first content change (the prepend), which snaps the list to the newest message. .sizeChanges did not preserve the prepend. .scrollPosition(id: $topId, anchor: .top) with .scrollTargetLayout() on the LazyVStack: the binding tracks the top row correctly, but after the prepend SwiftUI re-targets the binding to the new page's first row. Writing the previous id back, in the same update or on later run-loop turns, does not restore the position. Replacing LazyVStack with VStack fixes both cases, but the list holds hundreds of image rows and needs the lazy container for memory. What does work: reaching the backing UIScrollView (SwiftUIIntrospect), recording the visible rows' frames before the insert and adjusting contentOffset after layout. It works but is a lot of code for something that used to be one scrollTo. Questions Is it intended on iOS 27 that ScrollViewProxy.scrollTo does not scroll to a LazyVStack row that is not currently realized, or that the lazy stack keeps the currently visible rows stable in preference to the requested target? The WWDC26 lazy-stacks session describes the stack and scroll view coordinating the offset as estimates update; is scrollTo to an unrealized row now unsupported? Is there a supported SwiftUI way on iOS 27 to keep the visible rows in place when items are prepended to a LazyVStack, or to scroll reliably to an unrealized row? For example a ScrollPosition usage or an anchor role I am missing. If not, is adjusting the UIScrollView offset the expected approach, or is List now the recommended container for chat-style lists with bidirectional paging? I have filed this as FB24968838 with the sample project attached.
1
0
448
4w
Toolbar background behaviour
Say i have a scrollview: I find it’s dumb how if you have the safe area inset or any kind of element below the toolbar, the background of those will extend to the top edge of the screen (by default), yet if the scrollview scrolls to the toolbar the toolbar background just “appears”, covering the existing background— its even worse cuz the toolbar background is there by default even when you didn’t set it in code. It seems more like a bug; I feel like this is something the SwiftUI team should improve upon. How about disabling toolbar background by default? Just wanted to get some more perspectives.
0
0
390
Oct ’26
How does the AppStore app create an extra long toolbar
not sure if you guys can see with just image, but the scroll content is able to show underneath the section with the segmented pickers, and the section the background blends totally smoothly with the toolbar. from my own attempts, I am not able to make a extra long toolbar, and if i added a row just underneath the toolbar, the effect of scrolling the content under the row does not produce the effect.. I'm just wondering how Apple made this. did they just built the toolbar custom without even using swiftui toolbar? yes i am aware this is an older version of iOS, but I still want to know. thank you.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
284
Oct ’26
Hard scroll edge effect
The example they gave for the hard scroll edge effect is the calendar app, but Idk if this is a bad example or if i am missing something, because the calendar app theres a date picker row below the toolbar, and from my testing, whenever theres some element between the toolbar and the scrollview, the fade and blur effect does not happen -- so in fact, the hard scroll edge effect is completely unnecessary.
0
0
125
Oct ’26
Layout glitch after rotation when using UIWindowScene sizeRestrictions on iPadOS 26
Hi everyone, I am experiencing a strange rendering issue on iPadOS 26 when sizeRestrictions.minimumSize is set on a UIWindowScene. After rotating the device and then rotating it back to the original orientation, the window appears to be stretched based on its previous dimensions. This resulting "stretched" area does not resize or redraw correctly, leaving a significant black region on the screen. Interestingly, as soon as I interact with the window (e.g., a slight drag or touch), the UI snaps back to its intended state and redraws perfectly. Here is a sample code and capture of behavior. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } windowScene.sizeRestrictions?.minimumSize = CGSize( width: 390, height: 844 // larger than the height of iPad in landscape ) // initialize... } } Has anyone else encountered this behavior? If so, are there any known workarounds to force a layout refresh or prevent this "ghost" black area during the rotation transition? Any insights would be greatly appreciated. Thanks!
2
0
1.2k
Oct ’26
UIImage.pngData() exports incorrect translucent colors in 16-bit PNGs
Hi there. I was responding to some user feedback reported in this PR, that suggests UIImage 16-bit PNG exports may incorrectly handle alpha premultiplication. I put together a public repro of the issue that you can find here demonstrating the issue via a playground. Here's an LLM-generated summary of the problem: On the iOS 26.5 simulator (23F77), I’m seeing UIImage.pngData() produce darker translucent colors when exporting a 16-bit image captured with UIGraphicsImageRenderer. For a pixel drawn with UIColor(white: 0.96, alpha: 0.5), the PNG stores approximately 0.48 for its RGB samples and 0.50 for alpha. This appears to retain premultiplied colors, whereas PNG requires unpremultiplied colors. Exporting the same CGImage through ImageIO’s default PNG destination produces the expected 0.96 RGB and 0.50 alpha. An 8-bit standard-range control renders correctly through both exporters. I assume this is a framework bug, but let me know if the behavior is expected for some reason. I've also filed feedback FB25109021 regarding this behavior. Thanks in advance.
0
0
188
Oct ’26
RotationCoordinator preview angle is wrong for UIRequiresFullScreen apps built with the iOS 27 SDK in Stage Manager
I'm seeing a camera preview rotation issue on iPadOS 27 that depends only on the SDK the app is linked against. I've filed it as FB25106148 and wanted to share it in case others hit the same problem. Sample project: https://github.com/bc-lee/avfoundation-rotation-coordinator-discrete-resizing-poc Setup Portrait-only iPad app with UIRequiresFullScreen = YES Front camera AVCaptureVideoPreviewLayer, rotated with AVCaptureDevice.RotationCoordinator, as in the AVCam sample: let coordinator = AVCaptureDevice.RotationCoordinator(device: device, previewLayer: previewLayer) // On every change of videoRotationAngleForHorizonLevelPreview: previewLayer.connection?.videoRotationAngle = coordinator.videoRotationAngleForHorizonLevelPreview iPad Pro 11-inch (4th generation), iPadOS 27.0.1, Stage Manager on, Rotation Lock off What happens after rotating the iPad from portrait to landscape Xcode 26.5 (iOS 26.5 SDK) Xcode 27.1 RC (iOS 27.1 SDK) App UI Stays upright for the user, letterboxed Stays in portrait and lies on its side with the device (discrete resizing, TN3192) videoRotationAngleForHorizonLevelPreview 180° 180° Camera preview Upright Sideways The source code and Info.plist are the same for both builds. interfaceOrientation, effectiveGeometry, window and screen bounds, and isInterfaceOrientationLocked are also identical between the two builds, so I couldn't find a public value that tells the two presentations apart. In the iOS 27 SDK build, applying videoRotationAngleRelative(toDeviceOrientation:) (new in iOS 27) for the scene's interface orientation, which gives 90°, instead of the horizon-level preview angle restores an upright preview. Questions Is videoRotationAngleForHorizonLevelPreview expected to reflect the discrete resizing presentation in iPadOS 27? Until that is resolved, is using videoRotationAngleRelative(toDeviceOrientation:) with the scene's interface orientation, only when linked against the iOS 27 SDK and running on iOS 27, a reasonable workaround? Has anyone else seen this, or found a better approach?
0
0
289
Oct ’26
NSToolbarItemViewer's min/max size is nan
When attempting to use Toolbar(id: "") this crash occurs immediately upon showing the window. FAULT: NSInternalInconsistencyException: NSToolbarItemViewer's min/max size is nan. This indicates an item's size has been changed during layout which is illegal; { NSAssertFile = "NSToolbarItemViewer.m"; NSAssertLine = 942; } If I comment out the toolbars, re-run show the window once, then re-add id: the window properly displays, allows customization and does not error unless I clear data within ~/Library/Containers.
1
0
437
Oct ’26
Custom floating bottom right button
I have a floating bottom right button in my app (similar to twitter/x's blue compose button). I have no tab bar. When moving to the duo, this floating button now appears to the left of an empty tabbar/toolbar area on the right of the device. Ideally I want it to be inside the new tabbar/toolbar area when on the duo, as otherwise its wasted space. Is there anything new/inbuilt that I can leverage to manage this? Can I put my button into some container somewhere so that its the bottom right of the screen on an iPhone and automatically move to the toolbar area on duo? Something like a single item, right aligned, tabbar would be a great option. But the new liquid glass tabbar comes with too many restrictions on colors/styling I'm trying to find a way to avoid having logic like this in the app, as device specific logic becomes a maintenance issue int he future: if device == duo { // create toolbar button } else { // create button button and appen } d to window
Topic: UI Frameworks SubTopic: UIKit
3
2
644
Oct ’26
Can a custom keyboard extend its background into the system-owned top and bottom area
Hello Apple Developer Community, I am developing Keyboard Atelier, a Korean custom keyboard built with Swift, UIKit, and UIInputViewController. Is there a supported way to apply a user-selected background color or image across the entire keyboard presentation, including the surrounding system-owned areas? Problem On an iPhone, we observe a strip above our keyboard extension’s visible content and a separate bottom area containing the system globe and dictation controls. When we apply a custom background to our extension, these surrounding areas retain a different background. This makes our keyboard look like a rectangular panel placed inside a separate system frame. Our product lets users customize keycaps and keyboard backgrounds. We want their selected color or image to appear continuous across the entire keyboard presentation. What we have tested We compared an opaque white root-view background with a clear root-view background in an isolated simulator test. With the opaque background, the boundaries above and below the extension were visible. Removing our own top padding did not eliminate the upper strip. Setting the root view’s backgroundColor to UIColor.clear made the backgrounds appear visually continuous in both light and dark appearances. However, this only reveals the default system background. It does not Questions Is there a public API or supported configuration that lets a custom keyboard specify the background color of the surrounding system-owned areas? Can a custom keyboard supply a background image that extends into those areas, including beneath the system globe and dictation controls? If neither is supported, what is the documented boundary of background customization for a keyboard extension? Is Feedback Assistant the appropriate place to request this capability? iOS should retain control of the system buttons, including their behavior, accessibility, touch targets, and contrast adjustments. We are asking to customize the background behind them while preserving their functionality. The solution must be suitable for App Store distribution and work when the keyboard is used in other apps, without requiring changes to those host apps. Reproduction steps Enable the custom keyboard in Settings > General > Keyboard > Keyboards. Open a UITextView in the containing app. Switch to the custom keyboard. Set the keyboard extension’s root-view background to an opaque white color while using dark appearance. Observe the different backgrounds above and below the extension’s content. Compare this with a build using UIColor.clear for the root-view background. Implementation Swift and UIKit UIInputViewController keyboard extension Test host: a UIKit UITextView in the containing app Light and dark appearances tested RequestsOpenAccess = false Please point me to any relevant API or documentation, or clarify whether this would require a new API. Thank you.
Topic: UI Frameworks SubTopic: UIKit
1
2
153
Oct ’26
Some discussion on gestureRecognizers
I would appreciate some feedback on this simple technical point. When a gesture is defined in code, it is simply added to the view with myFirstView.addGestureRecognizer(someGesture) That's fine. But, if by mistake, the same gesture is added later to another view myOtherView.addGestureRecognizer(someGesture) myFirstView will not receive anymore the notification. That's well known and documented, because in fact the gesture references the view and can only reference one. So my point: this may be a bit misleading, as API let one believe that the gesture is attached to the view ; hence, why not attach to a second view ? wouldn't it be better to have API where view is explicitly "attached" to gesture ? someGesture.attach(to: myFirstView) Doing so, if I later someGesture.attach(to: myOtherView) it would be clearer I am changing the attached view. I noted that when we define a gesture in IB, we can only connect from the view to the gesture, not from gesture to the view which seems to follow the same logic. A simple extension does it: extension UITapGestureRecognizer { func attach(to view: UIView) { view.addGestureRecognizer(self) } } Any thought ? PS: I'm amazed by code completion. I just typed extension UITapGestureRecognizer { func attach(to view: UIView) and it completed automatically the code with view.addGestureRecognizer(self)
1
0
473
Oct ’26
CarPlay BANNERS ?!
I downloaded the CarPlay Simulator from Additional Tools for Xcode 27, but I can't find a way to test the navigation banners on the left or right side Several users have complained, and one of them finally sent me a photo. It looks fine in my simulator but not on their CarPlay screen How do we test those edge cases scenarios? This is my Simulator, looks fine And this is user's photo clearly showing the navigation banners in a different position
1
0
194
Oct ’26
Screen orientation on iPad
Xcode version 26.6 (17F113) MyOwnKeyboard-PAD app looks OK using simulator iPad Air 11-inch(M4). It automatically reformats to all orientations using only left and right landscape selected in General, Deployment Info. The submitted app 1.9 (4) had the portrait checked which was an error. I tried to update to version to 1.10 without portrait and upside down, but Validation states it must have all orientations needed. I tried setting all orientations and the simulator cuts off the sides. I am using a new mini M4 with Tahoe 26.6.2 Converted from an older developer mini using Migration Assistant. After conversion Xcode could not find xcspace files and apps locked up. I had to create new apps with different bundles which got conflicted in AppConnects causing rejects. When new versions are submitted, old versions cannot be removed because of submission states. Causing similar binaries, design and scam. I got trapped in the process! I have replied to AppConnect ref. binaries, design and scam. I hope someone can straighten this mess out. The good new is the free MyOwnKeyboard-PHONE analytics look OK with 4,000 impressions and 38 downloads and 172 product page reviews. It's a start! Thank you. Charlie Coupe Designer/Coder 2026sep16
2
0
734
Oct ’26
iPhone Duo: navigation bar item briefly moves to vertical bar during fullScreen dismissal despite .disabled
On the folded iPhone Duo display, a navigation bar item briefly moves into the vertical bar during dismissal of a full-screen modal, then jumps back to the top. Both navigation controllers consistently return .disabled from preferredVerticalBarBehavior, with childForPreferredVerticalBarBehavior returning nil. Environment Xcode 27.1 RC (27A9275), iOS 27.1 SDK, iPhone Duo simulator, folded outer display in portrait. Steps to reproduce Run the single-file UIKit example below in a scene-based app with a generated launch screen and no main storyboard. Tap the gear button on the Home screen to present Settings using .fullScreen. Tap the close button on Settings. Watch the Home screen's gear button during the dismissal animation. Expected The gear button stays in the top horizontal navigation bar throughout the transition, because the vertical bar preference is .disabled on both navigation controllers. Actual For part of the dismissal, the gear button appears below the status icons in the right-hand vertical bar region. It then jumps back to the top horizontal bar. The underlying tab bar also temporarily moves from the bottom to the right before returning. This reproduces with an otherwise empty view, standard UIKit containers, and the default bar appearance. No app code changes safeAreaInsets, bar frames, or animation timing. During the presentation/dismissal cycle, the Home view's logged right safe-area inset changes from 0 to 88 points and back to 0. In our app, content constrained to the safe area visibly narrows during the same transient change. In separate comparisons, returning .disabled from the root tab controller and content controllers, or requesting setNeedsUpdateOfVerticalBarConfiguration in appearance callbacks, did not eliminate the issue. Changing the modal to .overFullScreen avoided it in the tested simulator, but changes the underlying view controller lifecycle. The example below intentionally keeps .fullScreen to reproduce the problem. Is this expected behavior, or a known UIKit issue? Is there a supported way to keep .disabled effective throughout a fullScreen presentation/dismissal? Has this been addressed in a newer SDK/runtime? I have not tested iOS 27.2 or a physical Duo device. Minimal reproduction (one Swift file): import UIKit @main final class DemoAppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { let configuration = UISceneConfiguration(name: "Demo", sessionRole: session.role) configuration.delegateClass = DemoSceneDelegate.self return configuration } } final class DemoSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let home = DemoController() home.title = "首页" let navigation = DemoNavigationController(rootViewController: home) navigation.tabBarItem = UITabBarItem(title: "首页", image: UIImage(systemName: "house"), selectedImage: nil) let tabs = UITabBarController() if #available(iOS 18.0, *) { tabs.mode = .tabBar } tabs.viewControllers = [navigation] let window = UIWindow(windowScene: scene) window.rootViewController = tabs self.window = window window.makeKeyAndVisible() } } final class DemoNavigationController: UINavigationController { // 与音剪一致:导航容器固定横向栏,不转发给子页面。 @available(iOS 27.1, *) override var preferredVerticalBarBehavior: UIVerticalBarBehavior { .disabled } @available(iOS 27.1, *) override var childForPreferredVerticalBarBehavior: UIViewController? { nil } } final class DemoController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground if title == "设置" { navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction { [weak self] _ in self?.dismiss(animated: true) }) } else { navigationItem.rightBarButtonItem = UIBarButtonItem( image: UIImage(systemName: "gearshape"), primaryAction: UIAction { [weak self] _ in let settings = DemoController() settings.title = "设置" let navigation = DemoNavigationController(rootViewController: settings) navigation.modalPresentationStyle = .fullScreen self?.present(navigation, animated: true) }) } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() print("[DuoDemo] \(title ?? "") safe=\(view.safeAreaInsets) nav=\(navigationController?.navigationBar.frame ?? .zero) tab=\(tabBarController?.tabBar.frame ?? .zero)") } }
Replies
0
Boosts
2
Views
501
Activity
3w
UIScreen.screens.count differs on iPhone Duo sims depending on if app is IOS 26 SDK, or iOS 27 SDK
Hi there, My app uses UIScreen.screens.count (deprecated) to predict whether mirroring is happening on older iOS devices I noticed that the number of screens is different between iOS 26 SDK apps, and iOS 27 SDK apps. Can I expect that iOS 26 SDK apps will continue to return 1 screen like below for the iPhone Duo release?. I assume it's like this is to maximise compatibility. App built with SDK 26 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 1 App built with SDK 27 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 2 Thanks for the help! Sam
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
4
Boosts
0
Views
388
Activity
3w
iPhone Duo - globe button appeared in RC 1 - intended change or bug?
In Xcode 27.1 RC 1 the native keyboard layout has been changed and now it shows the globe button. It looks like a bug but I'm not sure. Is the keyboard going to display the globe button in the final release? On top of that, the keyboard extension tells not to show its own globe button, so it's another point confirming that this is RC 1 regression bug. Xcode 27.1 Beta 1: Xcode 27.1 RC 1:
Replies
3
Boosts
0
Views
1.1k
Activity
3w
SwiftData Sectioning iOS 27
I try Apple: Adopting SwiftData for a Core Data App . But I have error " 'init(filter:sort:transaction:sectionBy:)' requires the types '[Trip]' and 'SectionedResults<Array.Element, String>' (aka 'SectionedResults<Trip, String>') be equivalent" at code line Query(filter: filter, sort: [sortDescriptor], sectionBy: sectionBy)
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
383
Activity
3w
LiveCommunicationKit: Handle.displayName is never shown — the call UI and Recents show Handle.value
On iOS [27.x (build)], LiveCommunicationKit shows Handle.value on every system surface and ignores Handle.displayName. That forces a choice that CallKit doesn't: Put a stable account id in value (as WWDC26 session 226 recommends, so Recents redial can identify the person), and the raw id appears on the incoming call screen, the banner and in Recents. Put the person's name in value so the UI reads correctly, and a redial from Recents hands back only the name, which can't reliably identify anyone. Minimal reproduction let configuration = ConversationManager.Configuration( ringtoneName: nil, iconTemplateImageData: nil, maximumConversationGroups: 1, maximumConversationsPerConversationGroup: 1, includesConversationInRecents: true, supportsVideo: false, supportedHandleTypes: [.generic, .phoneNumber, .emailAddress] ) let manager = ConversationManager(configuration: configuration) let remote = Handle(type: .generic, value: "u-1234", displayName: "Jane Appleseed") try await manager.reportNewIncomingConversation( uuid: UUID(), update: Conversation.Update(members: [remote], capabilities: []) ) Expected: the incoming call UI and the Recents row show "Jane Appleseed". Session 226 says displayName is "what the system shows when it can't match the handle to a contact". Tapping the Recents row delivers an INStartCallIntent whose contact personHandle.value is u-1234. Actual: the full-screen ring, the foreground banner and the Recents row all show u-1234. Tapping the row does deliver INStartCallIntent with personHandle.value == "u-1234", so redial works, but the user never sees the name. What we tried, all with the same result (the value is shown): Handle.Kind set to .generic, .phoneNumber or .emailAddress, with every kind listed in supportedHandleTypes Conversation.Update(localMember:) set to the local user's handle activeRemoteMembers set to the remote handle, and localMember plus activeRemoteMembers together Donating an INInteraction (an INStartCallIntent whose INPerson has personHandle set to the id, displayName set to the name and customIdentifier set to the id) when the conversation ends. The donation succeeds, but the Recents row and the redial payload don't change. CallKit comparison, same device: CXCallUpdate.remoteHandle = CXHandle(type: .generic, value: "u-1234") with localizedCallerName = "Jane Appleseed" shows the name on the ring and in Recents. A redial from Recents delivers personHandle.value == "u-1234". That's the behaviour we expected from LiveCommunicationKit. Questions: Is Handle.displayName meant to be shown when the handle doesn't match a contact? If so, is there a configuration step we're missing? If this is a bug, is there a supported way with LiveCommunicationKit to show a name while keeping a stable identifier for Recents redial? Filed as FB24933340. Device: iPhone 15 pro, iOS [27.0.1].
Replies
4
Boosts
0
Views
503
Activity
4w
WARNING: Application performed a reentrant operation in its NSTableView delegate. This warning will become an assert in the future.
Can anyone help to understand what is causing this warning message on this SampleCode. it happens when data in table gets updated it happens when I have lot of items in table and search for lets say # 6543 and then clear the search. "WARNING: Application performed a reentrant operation in its NSTableView delegate. This warning will become an assert in the future." If there are just few items in table, the warning is not there. And it started when updated to Xcode Version 14 and upward import SwiftUI import Foundation @main struct TestProjectSWIFTApp: App {     @StateObject var mydata: MyData = MyData()     var body: some Scene {         WindowGroup {             ContentView()                 .environmentObject(mydata)         }              } } struct ContentView: View {     @EnvironmentObject var mydata: MyData     var body: some View {         NavigationView{             NavigationLink("TABLE",  destination: MyTable())                      }     } } struct User: Identifiable {     let id: UUID = UUID()     var name: String     var score: Int } struct MyTable: View {     @EnvironmentObject var mydata: MyData     @State private var sortOrder = [KeyPathComparator(\User.name)]     @State var searchText: String = ""     var searchResults : [User] {         if searchText.isEmpty {             return mydata.alldata         } else {             return mydata.alldata.filter{$0.name.localizedCaseInsensitiveContains(searchText)}         }     }          var body: some View {                  Button("Generate new data", action: {             mydata.updateTable()         })                  Table(searchResults, sortOrder: $sortOrder) {             TableColumn("Score"){                 Text("\(Double($0.score))")             }             TableColumn("user", value: \.name)         }         .onChange(of: sortOrder) {             mydata.alldata.sort(using: $0)         }         .searchable(text: $searchText)     } } @MainActor class MyData : ObservableObject{     @Published var alldata: [User] = []               init(){         self.setData()     }          func setData(){         alldata = [             User(name: "User 1", score: 95),             User(name: "User 2", score: 80),             User(name: "User 3", score: 85)         ]     }          func updateTable(){         var newallData: [User] = []         var x = 0         while x < 10000{             newallData.append(User(name: "User #\(x)", score:  Int.random(in: 10..<999999)))                          x = x + 1         }         alldata = newallData     }      }
Replies
18
Boosts
5
Views
5.2k
Activity
4w
Live Activities: no minute-granularity self-updating countdown text; custom DiscreteFormatStyle types fail to decode in the system renderer
Summary There is no supported way for a Live Activity to display a self-updating countdown at minute granularity in the form transit riders expect — a bare "7 min" that ticks to "6 min" — even though Apple's own apps (Timer in the Dynamic Island, Maps ETA) display exactly this form. The API that should make this possible — Text(_ input: TimeDataSource<Date>, format:) with a custom DiscreteFormatStyle (added in iOS 18) — compiles and archives, but the rendered activity fails at decode time in the system renderer, so every region of the Live Activity displays grey placeholder boxes. What I'm building An NYC subway departures app. The app's design language everywhere (in-app, home screen widgets via baked timeline entries) is "7 min" / "Now". Real-world fidelity is minute-level: riders don't think in mm:ss. The Live Activity is the only surface that cannot match this design, because it can only use self-updating text between content updates, and none of the built-in live formats produce it. Built-in options and why each falls short Text(timerInterval:countsDown:) — mm:ss only; no minute-granularity mode (this is FB23091094). Also reserves maximum width (FB23091111). Text(date, style: .relative) — always appends a second unit ("7 min, 30 sec") and counts up ambiguously (unsigned) after the date passes. .reference(to:allowedFields:maxFieldCount:) (iOS 18) — closest usable option, but only spelled-out wide units with a mandatory preposition: "in 7 minutes". No abbreviated/narrow width option exists on SystemFormatStyle.DateReference. .offset(to:) (iOS 18) — measures time since the anchor, so an upcoming departure renders as a negative value ("−7 minutes"); inverted for countdown use, and also wide-units only. The bug: custom DiscreteFormatStyle fails to decode in the renderer A custom format style solves this completely — mine rendered exact "7 min"/"Now" strings and, by holding the full departure list, even advanced to the next train the moment one departed, all without waking the app: @available(iOS 18.0, *) struct TrainCountdownFormat: DiscreteFormatStyle { var departures: [Date] var rank: Int // 0 = closest upcoming train var fullText: Bool // "7 min" vs "7m" func format(_ now: Date) -> String { let upcoming = departures.filter { $0 > now }.sorted() guard rank < upcoming.count else { return "—" } let totalSeconds = Int(upcoming[rank].timeIntervalSince(now)) if totalSeconds < 60 { return "Now" } let minutes = totalSeconds / 60 return fullText ? "\(minutes) min" : "\(minutes)m" } func discreteInput(after input: Date) -> Date? { departures.compactMap { departure -> Date? in let seconds = departure.timeIntervalSince(input) guard seconds > 0 else { return nil } let intoMinute = seconds.truncatingRemainder(dividingBy: 60) return input.addingTimeInterval(intoMinute > 0 ? intoMinute : 60) }.min() } func discreteInput(before input: Date) -> Date? { departures.compactMap { departure -> Date? in let seconds = departure.timeIntervalSince(input) guard seconds > 0 else { return departure < input ? departure : departure.addingTimeInterval(-60) } let intoMinute = seconds.truncatingRemainder(dividingBy: 60) return input.addingTimeInterval(intoMinute - 60) }.max() } } // In the ActivityConfiguration views: Text(.currentDate, format: TrainCountdownFormat(departures: dates, rank: 0, fullText: true)) This compiles and the activity is created, but every presentation (compact trailing, expanded, lock screen) renders as grey placeholder boxes. The console shows the archive being rejected at decode time in the renderer process: WidgetRenderer_Activities: (WidgetRenderer) [com.apple.chrono:activityRendererClient-verbose] Failed to return view entry from archive for view model with tag dynamicIsland-compactTrailing with error: SwiftUI.AnyCodable<...SafelyCodableRequirement>...Errors.noType(mangledName: "7SwiftUI18TimeDataFormattingO10ResolvableVy_AA0cD6SourceVAAE11DateStorageOy10Foundation0H0V_G 27NowDepartingWidgetExtension10$1030be9a0yXZ20TrainCountdownFormatV G") i.e. the archived TimeDataFormatting.Resolvable wrapper references a type defined in the app's widget extension, which the system renderer cannot look up. Nothing in the DiscreteFormatStyle or Text(_:format:) documentation states that only system-defined format styles are renderable in Live Activities, and there is no compile-time or runtime diagnostic surfaced to the developer — the activity just renders blank. Requests (either would unblock this) Support custom DiscreteFormatStyle types in Live Activity rendering (e.g. by evaluating the format in the extension's process when pre-rendering discrete frames), or at minimum document the limitation and fail loudly instead of rendering placeholder boxes. Add minute-granularity and unit-width options to the built-in live formats: a showsSeconds/fields option on Text(timerInterval:) (FB23091094), and/or a units-width option (abbreviated/narrow) plus a "bare duration, no preposition, countdown sign convention" variant on SystemFormatStyle.DateReference / DateOffset. Steps to reproduce Create a Live Activity whose views use Text(.currentDate, format:) with any custom DiscreteFormatStyle (sample above). Start the activity; background the app. Observe the Dynamic Island and lock screen render grey placeholder boxes for every region, and WidgetRenderer_Activities logs Errors.noType for each view model tag. Expected: the custom format renders and updates at the boundaries reported by discreteInput(before:/after:), as it does for the system styles. Actual: decode failure in the renderer; entire activity renders as placeholders. Environment Xcode 27.0 (27A266a) iOS 27.0 simulator, iPhone 18 Pro (also applies to iOS 18+ per API availability) Widget extension deployment target: iOS 17.6 Related reports: FB23091094, FB23091111, forum thread https://developer.apple.com/forums/thread/834337
Replies
1
Boosts
0
Views
130
Activity
4w
iOS 27: ScrollViewProxy.scrollTo no longer reaches unrealized LazyVStack rows; how to preserve position when prepending?
I have a chat screen built with ScrollView { LazyVStack } and ScrollViewReader. Two things that worked through iOS 26 stopped working on iOS 27 (Xcode 27, iOS 27.0 simulator and device; unchanged code still works on the iOS 26.x simulator): Open at the newest message. On appear I call proxy.scrollTo(lastId, anchor: .bottom). On iOS 27 the list stops two or three rows above the bottom when the rows have variable heights (text bubbles mixed with 200pt images). Load older messages at the top without the list jumping. When the user reaches the top, I prepend 25 older messages and call proxy.scrollTo(previousTopId, anchor: .top) so the row they were reading stays put. On iOS 27 the call does nothing: the list stays at the top of the newly inserted page (offset stays at 0), which immediately re-triggers the load. Re-issuing scrollTo on every layout change for a short window (which is what made this reliable on iOS 26) has no effect on iOS 27. Minimal reproduction import SwiftUI struct Message: Identifiable, Hashable { let id: Int let height: CGFloat // simulates text vs. image bubbles } @MainActor final class ChatModel: ObservableObject { @Published var messages: [Message] = [] @Published var previousTopId: Int? // set when a page is prepended private var nextOldId = 1_000 init() { messages = (0..<25).map { Message(id: nextOldId - $0, height: Self.randomHeight()) }.reversed() nextOldId -= 25 } func loadOlder() { let top = messages.first!.id let page = (0..<25).map { Message(id: nextOldId - $0, height: Self.randomHeight()) }.reversed() nextOldId -= 25 messages.insert(contentsOf: page, at: 0) previousTopId = top // "keep this row at the top" } static func randomHeight() -> CGFloat { [44, 60, 90, 200, 260].randomElement()! } } struct ChatView: View { @StateObject private var model = ChatModel() var body: some View { ScrollViewReader { proxy in ScrollView { LazyVStack(spacing: 8) { // top sentinel: load older when it becomes visible Color.clear.frame(height: 1) .onAppear { model.loadOlder() } ForEach(model.messages) { m in RoundedRectangle(cornerRadius: 12) .fill(m.height >= 200 ? .orange.opacity(0.4) : .blue.opacity(0.3)) .frame(height: m.height) .overlay(Text("\(m.id)")) .padding(.horizontal) .id(m.id) } } } .onAppear { // (1) open at the newest message DispatchQueue.main.async { proxy.scrollTo(model.messages.last!.id, anchor: .bottom) } } .onChange(of: model.previousTopId) { _, id in // (2) restore the row that was at the top before the prepend guard let id else { return } DispatchQueue.main.async { var t = Transaction(); t.disablesAnimations = true withTransaction(t) { proxy.scrollTo(id, anchor: .top) } } } } } } Observed (1) Open at the newest message, scrollTo(lastId, anchor: .bottom) iOS 26.x: lands on the last row. iOS 27.0: stops 2–3 rows above the bottom. (2) Prepend 25 rows, then scrollTo(previousTopId, anchor: .top) iOS 26.x: the previous top row is at the top of the viewport. iOS 27.0: the offset stays at 0 and the new page's first row is at the top. What I have tried on iOS 27 Re-issuing scrollTo for 0.5s on every content-height or offset change (via GeometryReader preferences). No effect; the target row is not realized, and the visible rows are kept stable instead. .defaultScrollAnchor(.bottom) and .defaultScrollAnchor(.bottom, for: .sizeChanges): fixes the initial open, but the stored anchor is re-applied once on the first content change (the prepend), which snaps the list to the newest message. .sizeChanges did not preserve the prepend. .scrollPosition(id: $topId, anchor: .top) with .scrollTargetLayout() on the LazyVStack: the binding tracks the top row correctly, but after the prepend SwiftUI re-targets the binding to the new page's first row. Writing the previous id back, in the same update or on later run-loop turns, does not restore the position. Replacing LazyVStack with VStack fixes both cases, but the list holds hundreds of image rows and needs the lazy container for memory. What does work: reaching the backing UIScrollView (SwiftUIIntrospect), recording the visible rows' frames before the insert and adjusting contentOffset after layout. It works but is a lot of code for something that used to be one scrollTo. Questions Is it intended on iOS 27 that ScrollViewProxy.scrollTo does not scroll to a LazyVStack row that is not currently realized, or that the lazy stack keeps the currently visible rows stable in preference to the requested target? The WWDC26 lazy-stacks session describes the stack and scroll view coordinating the offset as estimates update; is scrollTo to an unrealized row now unsupported? Is there a supported SwiftUI way on iOS 27 to keep the visible rows in place when items are prepended to a LazyVStack, or to scroll reliably to an unrealized row? For example a ScrollPosition usage or an anchor role I am missing. If not, is adjusting the UIScrollView offset the expected approach, or is List now the recommended container for chat-style lists with bidirectional paging? I have filed this as FB24968838 with the sample project attached.
Replies
1
Boosts
0
Views
448
Activity
4w
Toolbar background behaviour
Say i have a scrollview: I find it’s dumb how if you have the safe area inset or any kind of element below the toolbar, the background of those will extend to the top edge of the screen (by default), yet if the scrollview scrolls to the toolbar the toolbar background just “appears”, covering the existing background— its even worse cuz the toolbar background is there by default even when you didn’t set it in code. It seems more like a bug; I feel like this is something the SwiftUI team should improve upon. How about disabling toolbar background by default? Just wanted to get some more perspectives.
Replies
0
Boosts
0
Views
390
Activity
Oct ’26
How does the AppStore app create an extra long toolbar
not sure if you guys can see with just image, but the scroll content is able to show underneath the section with the segmented pickers, and the section the background blends totally smoothly with the toolbar. from my own attempts, I am not able to make a extra long toolbar, and if i added a row just underneath the toolbar, the effect of scrolling the content under the row does not produce the effect.. I'm just wondering how Apple made this. did they just built the toolbar custom without even using swiftui toolbar? yes i am aware this is an older version of iOS, but I still want to know. thank you.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
284
Activity
Oct ’26
Hard scroll edge effect
The example they gave for the hard scroll edge effect is the calendar app, but Idk if this is a bad example or if i am missing something, because the calendar app theres a date picker row below the toolbar, and from my testing, whenever theres some element between the toolbar and the scrollview, the fade and blur effect does not happen -- so in fact, the hard scroll edge effect is completely unnecessary.
Replies
0
Boosts
0
Views
125
Activity
Oct ’26
Layout glitch after rotation when using UIWindowScene sizeRestrictions on iPadOS 26
Hi everyone, I am experiencing a strange rendering issue on iPadOS 26 when sizeRestrictions.minimumSize is set on a UIWindowScene. After rotating the device and then rotating it back to the original orientation, the window appears to be stretched based on its previous dimensions. This resulting "stretched" area does not resize or redraw correctly, leaving a significant black region on the screen. Interestingly, as soon as I interact with the window (e.g., a slight drag or touch), the UI snaps back to its intended state and redraws perfectly. Here is a sample code and capture of behavior. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } windowScene.sizeRestrictions?.minimumSize = CGSize( width: 390, height: 844 // larger than the height of iPad in landscape ) // initialize... } } Has anyone else encountered this behavior? If so, are there any known workarounds to force a layout refresh or prevent this "ghost" black area during the rotation transition? Any insights would be greatly appreciated. Thanks!
Replies
2
Boosts
0
Views
1.2k
Activity
Oct ’26
UIImage.pngData() exports incorrect translucent colors in 16-bit PNGs
Hi there. I was responding to some user feedback reported in this PR, that suggests UIImage 16-bit PNG exports may incorrectly handle alpha premultiplication. I put together a public repro of the issue that you can find here demonstrating the issue via a playground. Here's an LLM-generated summary of the problem: On the iOS 26.5 simulator (23F77), I’m seeing UIImage.pngData() produce darker translucent colors when exporting a 16-bit image captured with UIGraphicsImageRenderer. For a pixel drawn with UIColor(white: 0.96, alpha: 0.5), the PNG stores approximately 0.48 for its RGB samples and 0.50 for alpha. This appears to retain premultiplied colors, whereas PNG requires unpremultiplied colors. Exporting the same CGImage through ImageIO’s default PNG destination produces the expected 0.96 RGB and 0.50 alpha. An 8-bit standard-range control renders correctly through both exporters. I assume this is a framework bug, but let me know if the behavior is expected for some reason. I've also filed feedback FB25109021 regarding this behavior. Thanks in advance.
Replies
0
Boosts
0
Views
188
Activity
Oct ’26
RotationCoordinator preview angle is wrong for UIRequiresFullScreen apps built with the iOS 27 SDK in Stage Manager
I'm seeing a camera preview rotation issue on iPadOS 27 that depends only on the SDK the app is linked against. I've filed it as FB25106148 and wanted to share it in case others hit the same problem. Sample project: https://github.com/bc-lee/avfoundation-rotation-coordinator-discrete-resizing-poc Setup Portrait-only iPad app with UIRequiresFullScreen = YES Front camera AVCaptureVideoPreviewLayer, rotated with AVCaptureDevice.RotationCoordinator, as in the AVCam sample: let coordinator = AVCaptureDevice.RotationCoordinator(device: device, previewLayer: previewLayer) // On every change of videoRotationAngleForHorizonLevelPreview: previewLayer.connection?.videoRotationAngle = coordinator.videoRotationAngleForHorizonLevelPreview iPad Pro 11-inch (4th generation), iPadOS 27.0.1, Stage Manager on, Rotation Lock off What happens after rotating the iPad from portrait to landscape Xcode 26.5 (iOS 26.5 SDK) Xcode 27.1 RC (iOS 27.1 SDK) App UI Stays upright for the user, letterboxed Stays in portrait and lies on its side with the device (discrete resizing, TN3192) videoRotationAngleForHorizonLevelPreview 180° 180° Camera preview Upright Sideways The source code and Info.plist are the same for both builds. interfaceOrientation, effectiveGeometry, window and screen bounds, and isInterfaceOrientationLocked are also identical between the two builds, so I couldn't find a public value that tells the two presentations apart. In the iOS 27 SDK build, applying videoRotationAngleRelative(toDeviceOrientation:) (new in iOS 27) for the scene's interface orientation, which gives 90°, instead of the horizon-level preview angle restores an upright preview. Questions Is videoRotationAngleForHorizonLevelPreview expected to reflect the discrete resizing presentation in iPadOS 27? Until that is resolved, is using videoRotationAngleRelative(toDeviceOrientation:) with the scene's interface orientation, only when linked against the iOS 27 SDK and running on iOS 27, a reasonable workaround? Has anyone else seen this, or found a better approach?
Replies
0
Boosts
0
Views
289
Activity
Oct ’26
NSToolbarItemViewer's min/max size is nan
When attempting to use Toolbar(id: "") this crash occurs immediately upon showing the window. FAULT: NSInternalInconsistencyException: NSToolbarItemViewer's min/max size is nan. This indicates an item's size has been changed during layout which is illegal; { NSAssertFile = "NSToolbarItemViewer.m"; NSAssertLine = 942; } If I comment out the toolbars, re-run show the window once, then re-add id: the window properly displays, allows customization and does not error unless I clear data within ~/Library/Containers.
Replies
1
Boosts
0
Views
437
Activity
Oct ’26
Custom floating bottom right button
I have a floating bottom right button in my app (similar to twitter/x's blue compose button). I have no tab bar. When moving to the duo, this floating button now appears to the left of an empty tabbar/toolbar area on the right of the device. Ideally I want it to be inside the new tabbar/toolbar area when on the duo, as otherwise its wasted space. Is there anything new/inbuilt that I can leverage to manage this? Can I put my button into some container somewhere so that its the bottom right of the screen on an iPhone and automatically move to the toolbar area on duo? Something like a single item, right aligned, tabbar would be a great option. But the new liquid glass tabbar comes with too many restrictions on colors/styling I'm trying to find a way to avoid having logic like this in the app, as device specific logic becomes a maintenance issue int he future: if device == duo { // create toolbar button } else { // create button button and appen } d to window
Topic: UI Frameworks SubTopic: UIKit
Replies
3
Boosts
2
Views
644
Activity
Oct ’26
Can a custom keyboard extend its background into the system-owned top and bottom area
Hello Apple Developer Community, I am developing Keyboard Atelier, a Korean custom keyboard built with Swift, UIKit, and UIInputViewController. Is there a supported way to apply a user-selected background color or image across the entire keyboard presentation, including the surrounding system-owned areas? Problem On an iPhone, we observe a strip above our keyboard extension’s visible content and a separate bottom area containing the system globe and dictation controls. When we apply a custom background to our extension, these surrounding areas retain a different background. This makes our keyboard look like a rectangular panel placed inside a separate system frame. Our product lets users customize keycaps and keyboard backgrounds. We want their selected color or image to appear continuous across the entire keyboard presentation. What we have tested We compared an opaque white root-view background with a clear root-view background in an isolated simulator test. With the opaque background, the boundaries above and below the extension were visible. Removing our own top padding did not eliminate the upper strip. Setting the root view’s backgroundColor to UIColor.clear made the backgrounds appear visually continuous in both light and dark appearances. However, this only reveals the default system background. It does not Questions Is there a public API or supported configuration that lets a custom keyboard specify the background color of the surrounding system-owned areas? Can a custom keyboard supply a background image that extends into those areas, including beneath the system globe and dictation controls? If neither is supported, what is the documented boundary of background customization for a keyboard extension? Is Feedback Assistant the appropriate place to request this capability? iOS should retain control of the system buttons, including their behavior, accessibility, touch targets, and contrast adjustments. We are asking to customize the background behind them while preserving their functionality. The solution must be suitable for App Store distribution and work when the keyboard is used in other apps, without requiring changes to those host apps. Reproduction steps Enable the custom keyboard in Settings > General > Keyboard > Keyboards. Open a UITextView in the containing app. Switch to the custom keyboard. Set the keyboard extension’s root-view background to an opaque white color while using dark appearance. Observe the different backgrounds above and below the extension’s content. Compare this with a build using UIColor.clear for the root-view background. Implementation Swift and UIKit UIInputViewController keyboard extension Test host: a UIKit UITextView in the containing app Light and dark appearances tested RequestsOpenAccess = false Please point me to any relevant API or documentation, or clarify whether this would require a new API. Thank you.
Topic: UI Frameworks SubTopic: UIKit
Replies
1
Boosts
2
Views
153
Activity
Oct ’26
Some discussion on gestureRecognizers
I would appreciate some feedback on this simple technical point. When a gesture is defined in code, it is simply added to the view with myFirstView.addGestureRecognizer(someGesture) That's fine. But, if by mistake, the same gesture is added later to another view myOtherView.addGestureRecognizer(someGesture) myFirstView will not receive anymore the notification. That's well known and documented, because in fact the gesture references the view and can only reference one. So my point: this may be a bit misleading, as API let one believe that the gesture is attached to the view ; hence, why not attach to a second view ? wouldn't it be better to have API where view is explicitly "attached" to gesture ? someGesture.attach(to: myFirstView) Doing so, if I later someGesture.attach(to: myOtherView) it would be clearer I am changing the attached view. I noted that when we define a gesture in IB, we can only connect from the view to the gesture, not from gesture to the view which seems to follow the same logic. A simple extension does it: extension UITapGestureRecognizer { func attach(to view: UIView) { view.addGestureRecognizer(self) } } Any thought ? PS: I'm amazed by code completion. I just typed extension UITapGestureRecognizer { func attach(to view: UIView) and it completed automatically the code with view.addGestureRecognizer(self)
Replies
1
Boosts
0
Views
473
Activity
Oct ’26
CarPlay BANNERS ?!
I downloaded the CarPlay Simulator from Additional Tools for Xcode 27, but I can't find a way to test the navigation banners on the left or right side Several users have complained, and one of them finally sent me a photo. It looks fine in my simulator but not on their CarPlay screen How do we test those edge cases scenarios? This is my Simulator, looks fine And this is user's photo clearly showing the navigation banners in a different position
Replies
1
Boosts
0
Views
194
Activity
Oct ’26
Screen orientation on iPad
Xcode version 26.6 (17F113) MyOwnKeyboard-PAD app looks OK using simulator iPad Air 11-inch(M4). It automatically reformats to all orientations using only left and right landscape selected in General, Deployment Info. The submitted app 1.9 (4) had the portrait checked which was an error. I tried to update to version to 1.10 without portrait and upside down, but Validation states it must have all orientations needed. I tried setting all orientations and the simulator cuts off the sides. I am using a new mini M4 with Tahoe 26.6.2 Converted from an older developer mini using Migration Assistant. After conversion Xcode could not find xcspace files and apps locked up. I had to create new apps with different bundles which got conflicted in AppConnects causing rejects. When new versions are submitted, old versions cannot be removed because of submission states. Causing similar binaries, design and scam. I got trapped in the process! I have replied to AppConnect ref. binaries, design and scam. I hope someone can straighten this mess out. The good new is the free MyOwnKeyboard-PHONE analytics look OK with 4,000 impressions and 38 downloads and 172 product page reviews. It's a start! Thank you. Charlie Coupe Designer/Coder 2026sep16
Replies
2
Boosts
0
Views
734
Activity
Oct ’26