I’m trying to understand the expected behavior of TabView when using .tabViewStyle(.page) on iPadOS with a hardware keyboard.
When I place a TabView in page mode, swipe gestures correctly move between pages. However, left and right arrow keys do nothing by default, even when the view is made focusable. This feels a bit surprising, since paging with arrow keys seems like a natural keyboard interaction when a keyboard is attached.
Right now, to get arrow-key navigation working, I have to manually:
Make the view focusable
Listen for arrow key presses
Update the selection state manually
This works, but it feels a little tedious for something that seems like it could be built-in.
import SwiftUI
struct PageTabsExample: View {
@State private var selection = 0
private let pageCount = 3
var body: some View {
TabView(selection: $selection) {
Color.red.tag(0)
Color.blue.tag(1)
Color.green.tag(2)
}
.tabViewStyle(.page)
.indexViewStyle(.page)
.focusable(true)
.onKeyPress(.leftArrow) {
guard selection > 0 else { return .ignored }
selection -= 1
return .handled
}
.onKeyPress(.rightArrow) {
guard selection < pageCount - 1 else { return .ignored }
selection += 1
return .handled
}
}
}
My questions:
Is this lack of default keyboard paging for page-style TabView intentional on iPadOS with a hardware keyboard?
Is there a built-in way to enable arrow-key navigation for page-style TabView, or is manual handling the expected approach?
Does my approach above look like the “SwiftUI-correct” way to do this, or is there a better pattern for integrating keyboard navigation with paging?
For this kind of behavior, is it generally recommended to use .onKeyPress like I’m doing here, or would .keyboardShortcut be more appropriate (for example, wiring arrow keys to actions instead)?
Any guidance or clarification would be greatly appreciated. I just want to make sure I’m not missing a simpler or more idiomatic solution.
Thanks!
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
I'm creating an app and I want the user to see the PNG image with the background removed in the widget, but I want the background to be transparent. I've seen this done before in some apps' CarPlay widgets. How can I do this?
When adding buttons to a sheet, on tvOS the text is blurred in the buttons, making it illegible. Feedback: FB21228496
(used GPT to extract an example from my project for a test project to attach here)
// ButtonBlurTestView.swift
// Icarus
//
// Test view to reproduce blurred button issue on tvOS
//
import SwiftUI
struct ButtonBlurTestView: View {
@State private var showSheet = false
@State private var selectedTags: [Int] = []
@State private var newTagName: String = ""
// Hardcoded test data
private let testTags = [
TestTag(id: 1, label: "Action"),
TestTag(id: 2, label: "Comedy"),
TestTag(id: 3, label: "Drama"),
TestTag(id: 4, label: "Sci-Fi"),
TestTag(id: 5, label: "Thriller")
]
var body: some View {
NavigationStack {
VStack {
Text("Button Blur Test")
.font(.title)
.padding()
Button("Show Test Sheet") {
showSheet = true
}
.buttonStyle(.borderedProminent)
.padding()
Text("Tap the button above to open a sheet with buttons inside a Form.")
.font(.caption)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding()
}
.navigationTitle("Blur Test")
.sheet(isPresented: $showSheet) {
TestSheetView(
selectedTags: $selectedTags,
newTagName: $newTagName,
testTags: testTags
)
}
}
}
}
struct TestSheetView: View {
@Environment(\.dismiss) private var dismiss
@Binding var selectedTags: [Int]
@Binding var newTagName: String
let testTags: [TestTag]
var body: some View {
NavigationStack {
VStack {
// Header
VStack {
Text("Testing")
.font(.title2)
.bold()
Text("Test TV Show")
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding()
// Form with buttons
Form {
Section(header: Text("Summary")) {
Text("This is a test")
.font(.subheadline)
.foregroundColor(.secondary)
}
Section(header: Text("Tags")) {
tagsSelectionView
}
}
}
.navigationTitle("Add")
#if !os(tvOS)
.navigationBarTitleDisplayMode(.inline)
#endif
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
ToolbarItem(placement: .confirmationAction) {
Button("Add") { dismiss() }
}
}
}
}
private var tagsSelectionView: some View {
VStack(alignment: .leading) {
// Tag pills in a grid
let columns = [GridItem(.adaptive(minimum: 80), spacing: 8)]
LazyVGrid(columns: columns, alignment: .leading, spacing: 8) {
ForEach(testTags, id: \.id) { tag in
TagPill(
tag: tag,
selected: selectedTags.contains(tag.id)
) {
if selectedTags.contains(tag.id) {
selectedTags.removeAll { $0 == tag.id }
} else {
selectedTags.append(tag.id)
}
}
}
}
Divider()
// Add new tag button
HStack {
TextField("New tag name", text: $newTagName)
#if os(tvOS)
.textFieldStyle(PlainTextFieldStyle())
#else
.textFieldStyle(RoundedBorderTextFieldStyle())
#endif
Button("Add") {
// Test action
newTagName = ""
}
.disabled(newTagName.trimmingCharacters(in: .whitespaces).isEmpty)
}
}
}
}
// Tag Pill - matches the structure from original project
private struct TagPill: View {
let tag: TestTag
let selected: Bool
let action: () -> Void
var body: some View {
Button(action: action) {
Text(tag.label)
.font(.callout)
.lineLimit(1)
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(
Capsule()
.fill(selected ? Color.accentColor : Color.secondary.opacity(0.15))
)
.overlay(
Capsule()
.stroke(selected ? Color.accentColor : Color.secondary.opacity(0.35), lineWidth: 1)
)
.foregroundStyle(selected ? Color.white : Color.primary)
.contentShape(Capsule())
}
.buttonStyle(.plain)
#if os(tvOS)
.focusable(true)
#endif
}
}
struct TestTag {
let id: Int
let label: String
}
#Preview {
ButtonBlurTestView()
}
In my UITableViewController when a sticky section header is replaced by the following header in succession, the cell below is revealed for a short time. This looks like a glitch to me. Is there a workaround to solve this?
The issue is best explained in video: https://youtube.com/shorts/JIEbFTTIDjA?feature=share
We have submitted a feedback for this issue: FB21230723
We're building a note-taking app for iOS and macOS that uses both UITextView and NSTextView.
When performing text input that involves a marked range (such as Japanese input) in a UITextView or NSTextView with a UITextViewDelegate or NSTextViewDelegate set, the text view's marked range (markedTextRange / markedRange()) has not yet been updated at the moment when shouldChangeTextIn is invoked.
UITextViewDelegate.textView(_:shouldChangeTextIn:replacementText:)
NSTextViewDelegate.textView(_:shouldChangeTextIn:replacementString:)
The current behavior is this when entering text in Japanese: (same for NSTextView)
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
print(textView.markedTextRange != nil) // prints out false
DispatchQueue.main.async {
print(textView.markedTextRange != nil) // prints out true
}
}
However, we need the value of markedTextRange right away in order to determine whether to return true or false from this method.
Is there any workaround for this issue?
The Paste button (using UIPasteControll) located on UINavigationBar is not shown at application startup on iOS/iPadOS 26.
This issue will disappear when device is rotated or window size is changed.
And this issue does not occur on iOS / iPadOS 18 and earlier.
I uploaded the sample project to github at the following URL. https://github.com/gpn-galapagos/PasteButtonApp.git
Has anyone had the same issue or knows a workaround?
The Problem
When using adjustsImageWhenAncestorFocused = true on a UIImageView in tvOS, the native focus halo effect does not respect the cornerRadius property set on the image view's layer.
The image itself correctly clips to the rounded corners, but the focus halo (the glowing outline that appears when the view is focused) always renders with square or nearly-square corners.
Code Example
let imageView = UIImageView()
imageView.layer.cornerRadius = 60
imageView.clipsToBounds = true
imageView.adjustsImageWhenAncestorFocused = true
imageView.image = posterImage
Result: The poster image displays with 60pt rounded corners as expected, but when focused, the halo effect has square corners - creating an obvious visual mismatch.
Expected Behavior
The focus halo should follow the same cornerRadius as the UIImageView. If I set a 60pt corner radius, both the image and its focus halo should have matching 60pt rounded corners.
Actual Behavior
The image respects cornerRadius and displays with rounded corners
The focus halo ignores cornerRadius and renders with square corners
This creates an inconsistent, unpolished appearance
Environment
tvOS 16.0+ (tested through tvOS 18)
Affects both Apple TV Simulator and physical devices
Occurs with any corner radius value above approximately 20-30pt
Use Case
This is a common scenario for media streaming apps. Movie and TV show poster cards typically use rounded corners (40-80pt) as part of modern UI design. Many apps like Netflix, Plex, and others use this design pattern.
The current behavior forces developers to choose between:
Using the beautiful native focus effect but with mismatched square halos
Implementing a completely custom focus effect from scratch, losing the native parallax, shadow, and halo animations
Neither option is ideal.
What I've Tried
Setting cornerRadius before and after adjustsImageWhenAncestorFocused
Different clipsToBounds configurations
Wrapping the image view in a container view with corner radius
Using layer.maskedCorners to specify which corners to round
Subclassing CALayer to intercept sublayers added by the focus system
None of these approaches affect the focus halo's corner radius.
Request
I would appreciate guidance on any of the following:
Is there a supported way to customize the focus halo's corner radius? The UIFocusHaloEffect class exists on iOS/iPadOS but is not available on tvOS.
Is this a bug that will be addressed? The focus system clearly reads some properties from the image view (like bounds), so it seems like cornerRadius should also be respected.
Is there a different API I should be using? Perhaps there's an alternative approach to achieve rounded corner poster cards with matching focus effects that I'm not aware of.
Additional Context
I've noticed that some third-party apps have achieved this effect, suggesting it may be possible through undocumented means. However, I would prefer to use a public, supported API to ensure compatibility with future tvOS updates.
Any guidance from Apple engineers or developers who have solved this would be greatly appreciated.
Thank you.
Topic:
UI Frameworks
SubTopic:
UIKit
AI's would have me believe that the header of a TableColumn in Table() can be modified to be interactive simply by adding a header: closure with a Button however no provided code actually compiles or reflects any documentation I can find.
Is it possible to put something besides a Text object in the header?
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi there!
We have an application that exists for more than 10 years (Appkit, Obj-C), and since the very beginning we're using CMD+ESC as a keyboard shortcut for a very important function in our app. Until now, this worked great.
Recently, when macOS 26.1 released our app started to not responding to CMD+ESC anymore for some of our customers - it seems like CMD+ESC never gets to our app at all. First, we though it's happening because Game Overlay is also using CMD+ESC by default, but when we turned that off, or switched that to something else in macOS's Keyboard preferences, the issue still persisted.
The, we realized this has something to do with iCloud - so, if you turn off iCloud, do a log out and log in to your computer, and it's magically starts working again, as it always did.
More strangely, this issue doesn't happen for everyone - for many of our customers, the issue seems to doesn't exist for some strange reason.
Anyone have any idea what could be happening here?
Topic:
UI Frameworks
SubTopic:
AppKit
My app doesn't respond on iPhone Air iOS 26.1.
After startup, my app shows the main view with a tab bar controller containing 4 navigation controllers. However, when a second-level view controller is pushed onto any navigation controller, the UI freezes and becomes unresponsive. The iPhone simulator running iOS 26.1 exhibits the same problem.
The debug profile shows CPU usage at 100%.
However, other devices and simulators do not have this problem.
Dear Forum,
after decades, I'm back to MacOS dev just for the need of it. Besides Mac, I'm also toying around with vintage IBM mainframe systems and therefore I'm in need for a good terminal emulation. So far, I use x3270 on my Apple Silicon M1 MacBook Air - nice. However, I can't compile it on my collection of vintage Macs (iMac G3, Cube G4) so I pondered to create it on my own using Cocoa (starting with MacOS X 10.4 Tiger up to the current level (on Sequoia) so that rules out Carbon. tn3270 X from Brown University works nice on those vintage Macs but misses some features. Having browsed some info about the Cocoa Text system, I wonder if that would be the right place to start.
At the end of the day, I need to be able to intercept all keystrokes, have more or less a fixed font 80x25 (136x25 etc..) col/row layout of protected and unprotected areas where text can be entered. Cusor should be visible and movable by using cursor control keys. I'd be happy for any suggestion on where to start here.
Kind regards
Michael
Topic:
UI Frameworks
SubTopic:
AppKit
Since updating to Tahoe and Xcode 26 I have found that the UISplitViewController.showDetailViewController() is not working in the iPhone version of my app (it is a universal app). I'm just trying to show a detail view after a tap on a UITableView item. The iPad versions are all working correctly. Has anyone else experienced this or have any advice about what may have changed?
Thanks in advance.
UIViewController's modalInPopover is deprecated and might disappear in the near future. Is there any replacement?
UIViewController's presentViewController:animated:completion is not an equivalent because the modal style cannot be changed while the controller is already presented.
It seems to be that the functionality of the method setViewController:forColumn: in the column-style layout of a UISplitViewController has changed.
iOS 18: setViewController:forColumn: pushes a new view controller onto the UINavigationController if it existed before the call.
iOS 26: setViewController:forColumn: sets or replaces the view controller with a new view controller as a root of a new UINavigationController.
My questions:
what is the intended behavior? I did not find any documentation about a change.
how do I replace in iOS 18 the old view controller with the new view controller passed to setViewController:forColumn:?
I am trying to implement a common UX/UI pattern: one view with rounded corners transitioning to a view that fills the screen (N.B. having the display's corner radius).
I got this to work if both corner radiuses are equal to that of the display (see first GIF).
However, I cannot seem to get it to work for arbitrary corner radiuses of the smaller view (i.e., the one that does not fill the screen).
I expected the be able to combine ContainerRelativeShape with .containerShape (see code), but this left me with a broken transition animation (see second GIF).
import SwiftUI
struct ContentView: View {
@Namespace private var animation
@State private var selectedIndex: Int?
var body: some View {
ZStack {
if let selectedIndex = selectedIndex {
ContainerRelativeShape()
.fill(Color(uiColor: .systemGray3))
.matchedGeometryEffect(id: "square-\(selectedIndex)", in: animation)
.ignoresSafeArea()
.onTapGesture {
withAnimation() {
self.selectedIndex = nil
}
}
.zIndex(1)
}
ScrollView {
VStack(spacing: 16) {
ForEach(0..<20, id: \.self) { index in
if selectedIndex != index {
ContainerRelativeShape() // But what if I want some other corner radius to start with?
.fill(Color(uiColor: .systemGray5))
.matchedGeometryEffect(id: "square-\(index)", in: animation)
.aspectRatio(1, contentMode: .fit)
.padding(.horizontal, 12)
.onTapGesture {
withAnimation() {
selectedIndex = index
}
}
// .containerShape(RoundedRectangle(cornerRadius: 20))
// I can add this to change the corner radius, but this breaks the transition of the corners
} else {
Color.clear
.aspectRatio(1, contentMode: .fit)
.padding(.horizontal, 12)
}
}
}
.padding(.vertical, 16)
}
}
}
}
#Preview {
ContentView()
}
What am I missing here? How can I get this to work? And where is the mistake in my reasoning?
Hi everyone,
I’m working on a screen that uses a single SwiftUI List composed of:
a top block (statistics, month picker, year selector, total, Entrata/Uscita picker).
a list of transactions grouped by day, each group inside its own Section.
each row is a fully custom card with rounded corners (RoundedCornerShape)
I’m correctly removing all separators using:
.listRowSeparator(.hidden)
.listSectionSeparator(.hidden)
.scrollContentBackground(.hidden)
.listStyle(.plain)
Each row is rendered like this:
TransazioneSwipeRowView(...)
.listRowInsets(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
.listRowBackground(Color.clear)
However, I still see thin horizontal lines appearing between:
the search bar and the top block
the top block and the start of the list
between rows inside the grouped section
sometimes at the bottom of a Section
These lines are NOT:
Divider()
system separators
backgrounds
row borders
They seem to be “ghost lines” automatically generated by SwiftUI’s List when multiple consecutive rows or sections are present.
Goal
I want to remove these lines completely while keeping:
native SwiftUI List
native scroll behavior
swipe-to-delete support
grouping by Section
custom card-like rows with rounded corners
transparent backgrounds
What I already tried
.plain, .grouped, .insetGrouped list styles
.listRowSeparator(.hidden) and .listSectionSeparator(.hidden)
.scrollContentBackground(.hidden)
clearing all backgrounds
adjusting/removing all padding and insets
Spacer(minLength: 0) experiments
rebuilding the layout using ScrollView + LazyVStack
(works perfectly — no lines — BUT loses native swipe-to-delete)
There are no Divider() calls anywhere, and no background colors producing borders.
Question
Is this a built-in behavior of SwiftUI’s List in .plain style when using multiple custom rows,
or is there an officially supported way to eliminate these lines entirely?
Is there a recommended combination of modifiers to achieve:
a List with grouped Sections
fully custom rows with rounded backgrounds
absolutely no horizontal separators, even in the empty spaces between sections?
Any guidance, documented workarounds, WWDC references, or official recommendations would be greatly appreciated.
Thanks in advance!
Hello everyone!
I found a weird behavior with the animation of Menucomponent on iOS 26.1
When the menu disappear the animation is very glitchy
You can find here a sample of code to reproduce it
@available(iOS 26.0, *)
struct MenuSample: View {
var body: some View {
GlassEffectContainer {
HStack {
Menu {
Button("Action 1") {}
Button("Action 2") {}
Button("Delete", role: .destructive) {}
} label: {
Image(systemName: "ellipsis")
.padding()
}
Button {} label: {
Image(systemName: "xmark")
.padding()
}
}
.glassEffect(.clear.interactive())
}
}
}
@available(iOS 26.0, *)
#Preview {
MenuSample()
.preferredColorScheme(.dark)
}
I did two videos:
iOS 26.0
iOS 26.1
Thanks for your help
I'm building a macOS app using SwiftUI, and I want to create a draggable floating webcam preview window
Right now, I have something like this:
import SwiftUI
import AVFoundation
struct WebcamPreviewView: View {
let captureSession: AVCaptureSession?
var body: some View {
ZStack {
if let session = captureSession {
CameraPreviewLayer(session: session)
.clipShape(RoundedRectangle(cornerRadius: 50))
.overlay(
RoundedRectangle(cornerRadius: 50)
.strokeBorder(Color.white.opacity(0.2), lineWidth: 2)
)
} else {
VStack(spacing: 8) {
Image(systemName: "video.slash.fill")
.font(.system(size: 40))
.foregroundColor(.white.opacity(0.6))
Text("No Camera")
.font(.caption)
.foregroundColor(.white.opacity(0.6))
}
}
}
.shadow(color: .black.opacity(0.3), radius: 10, x: 0, y: 5)
}
}
struct CameraPreviewLayer: NSViewRepresentable {
let session: AVCaptureSession
func makeNSView(context: Context) -> NSView {
let view = NSView()
view.wantsLayer = true
let previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = .resizeAspectFill
previewLayer.frame = view.bounds
view.layer = previewLayer
return view
}
func updateNSView(_ nsView: NSView, context: Context) {
if let previewLayer = nsView.layer as? AVCaptureVideoPreviewLayer {
previewLayer.frame = nsView.bounds
}
}
}
This is my SwiftUI side code to show the webcam, and I am trying to create it as a floating window which appears on top of all other apps windows etc. however, even when the webcam is clicked, it should not steal the focus from other apps, the other apps should be able to function properly as they already are.
import Cocoa
import SwiftUI
class WebcamPreviewWindow: NSPanel {
private static let defaultSize = CGSize(width: 200, height: 200)
private var initialClickLocation: NSPoint = .zero
init() {
let screenFrame = NSScreen.main?.visibleFrame ?? .zero
let origin = CGPoint(
x: screenFrame.maxX - Self.defaultSize.width - 20,
y: screenFrame.minY + 20
)
super.init(
contentRect: CGRect(origin: origin, size: Self.defaultSize),
styleMask: [.borderless],
backing: .buffered,
defer: false
)
isOpaque = false
backgroundColor = .clear
hasShadow = false
level = .screenSaver
collectionBehavior = [
.canJoinAllSpaces,
.fullScreenAuxiliary,
.stationary,
.ignoresCycle
]
ignoresMouseEvents = false
acceptsMouseMovedEvents = true
hidesOnDeactivate = false
becomesKeyOnlyIfNeeded = false
}
// MARK: - Focus Prevention
override var canBecomeKey: Bool { false }
override var canBecomeMain: Bool { false }
override var acceptsFirstResponder: Bool { false }
override func makeKey() {
}
override func mouseDown(with event: NSEvent) {
initialClickLocation = event.locationInWindow
}
override func mouseDragged(with event: NSEvent) {
let current = event.locationInWindow
let dx = current.x - initialClickLocation.x
let dy = current.y - initialClickLocation.y
let newOrigin = CGPoint(
x: frame.origin.x + dx,
y: frame.origin.y + dy
)
setFrameOrigin(newOrigin)
}
func show<Content: View>(with view: Content) {
let host = NSHostingView(rootView: view)
host.autoresizingMask = [.width, .height]
host.frame = contentLayoutRect
contentView = host
orderFrontRegardless()
}
func hide() {
orderOut(nil)
contentView = nil
}
}
This is my Appkit Side code make a floating window, however, when the webcam preview is clicked, it makes it as the focus app and I have to click anywhere else to loose the focus to be able to use the rest of the windows.
Hi
Given a simple multiplatform app about Mushrooms, stored in SwiftData, hosted in iCloud using a TextEditor
@Model
final class Champignon: Codable {
var nom: String = ""
../..
@Attribute(.externalStorage)
var attributedStringData: Data = Data()
var attributedString: AttributedString {
get {
do {
return try JSONDecoder().decode(AttributedString.self,
from: attributedStringData)
} catch {
return AttributedString("Failed to decode AttributedString: \(error)")
}
}
set {
do {
self.attributedStringData = try JSONEncoder().encode(newValue)
} catch {
print("Failed to encode AttributedString: \(error)")
}
}
}
../..
Computed attributedString is used in a TextEditor
private var textEditorView: some View {
Section {
TextEditor(text: $model.attributedString)
} header: {
HStack {
Text("TextEditor".localizedUppercase)
.foregroundStyle(.secondary)
Spacer()
}
}
}
Plain Text encode, decode and sync like a charm through iOS and macOS
Use of "FontAttributes" (Bold, Italic, …) works the same
But use of "ForegroundColorAttributes" trigger an error :
Failed to decode AttributedString: dataCorrupted(Swift.DecodingError.Context(codingPath: [_CodingKey(stringValue: "Index 3", intValue: 3), AttributeKey(stringValue: "SwiftUI.ForegroundColor", intValue: nil), CodableBoxCodingKeys(stringValue: "value", intValue: 1)], debugDescription: "Platform color is not available on this platform", underlyingError: nil))
Is there a way to encode/decode attributedString data platform conditionally ?
Or another approach ?
Thanks for advices
Issue Summary:
iOS 26 UI components are not visible in the Expo app when installed via TestFlight. All components render correctly in local builds or when running with expo run:ios.
Details:
The app is built using Expo managed workflow.
iOS 26-specific UI components do not appear in TestFlight builds.
The same components display correctly in local builds and simulators.
Test device: iPhone running iOS 26.1.
There are no crashes or runtime errors; only the components are missing.
This issue occurs only in TestFlight/release builds.
Expected Behavior:
All iOS 26 UI components should render in TestFlight builds the same way they do in local builds.
Actual Behavior:
Components fail to render or are completely missing.
Device Information:
Device: iPhone
iOS Version: 26.1
Distribution: TestFlight
Local Build: Working correctly
Additional Notes:
This may be related to Expo release build optimization or iOS 26 SDK compatibility.