We have used searchable modifier with automatic or toolbar placement. When user tap on keyboard's search button it doesn't trigger onSubmit modifier.
However if placement is navigationBarDrawer it is working fine.
.searchable(text: $searchText, placement: .automatic, prompt: "Search")
.onSubmit(of: .search) {
print("Search submitted")
}
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
Activity
PhaseAnimator seems a good fit to play gifs in SwiftUI:
struct ContentView: View {
let frames = [UIImage(named: "frame-1")!, UIImage(named: "frame-2")!]
var body: some View {
PhaseAnimator(frames.indices) { index in
Image(uiImage: frames[index])
}
}
}
The problem is that by default, there's an opacity transition between phases. So I tried using transition(.identity):
Image(uiImage: gif[index])
.transition(.identity)
.id(index)
It doesn't work. It stays frozen on the first frame.
It does work if I set the transition to a small offset value:
Image(uiImage: gif[index])
.transition(.offset(x: 0, y: 0.1))
.id(index)
It does feel a bit hacky, though.
Is this the expected behavior for .transition(.identity), or is it a bug?
On iPhone, I would like to have a more button at the top right of the navigation bar, a search field in the bottom toolbar, and a plus button to the right of the search field. I've achieved this via the code below.
But on iPad they should be in the navigation bar at the trailing edge from left to right: plus, more, search field. Just like the Shortcuts app, if there's not enough horizontal space, the search field should collapse into a button, and with even smaller space the search bar should become full-width under the navigation bar.
Right now on iPad the search bar is full width under the navigation bar, more at top right, plus at bottom middle, no matter how big the window is.
How can I achieve that? Any way to specify them for the system to more automatically do the right thing, or would I need to check specifically for iPhone vs iPad UIDevice to change the code?
struct ContentView: View {
@State private var searchText = ""
var body: some View {
NavigationStack {
VStack {
Text("Hello, world!")
}
.navigationTitle("Test App")
.searchable(text: $searchText)
.toolbar {
ToolbarItem {
Menu {
//...
} label: {
Label("More", systemImage: "ellipsis")
}
}
DefaultToolbarItem(kind: .search, placement: .bottomBar)
ToolbarSpacer(.fixed, placement: .bottomBar)
ToolbarItem(placement: .bottomBar) {
Button {
print("Add tapped")
} label: {
Label("Add", systemImage: "plus")
}
}
}
}
}
}
In the Console, when presenting my view in a horizontally compact environment, I see:
UINavigationController for collapsing UISplitViewController about to push view controller <UINavigationController: 0x107933c00>
This message repeats infinitely, until the Xcode debugger eventually says:
QUARANTINED DUE TO HIGH LOGGING VOLUME
Of note is that this only occurs in the beta, does not occur when using the iOS 18.x SDK, and only occurs in a compact environment.
EDIT:
This occurs only when setting the secondary column of a doubleColumn UISplitViewController:
splitVC.setViewController(secondary, for: .secondary)
EDIT 2 and WORKAROUND:
If this action is deferred until after viewDidAppear, it self-resolves:
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let deferredSecondaryViewController {
splitVC.showDetailViewController(deferredSecondaryViewController, sender: nil)
}
}
Topic:
UI Frameworks
SubTopic:
UIKit
When compiled on Xcode 16.4.0:
When compiled on Xcode 26:
The code:
import SwiftUI
struct SearchBarController: UIViewRepresentable {
@Binding var text: String
var placeholderText: String
class Coordinator: NSObject, UISearchBarDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
}
func makeUIView(context: Context) -> UISearchBar {
let searchBar = UISearchBar(frame: .zero)
searchBar.delegate = context.coordinator
searchBar.placeholder = placeholderText
searchBar.searchBarStyle = .minimal
return searchBar
}
func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
}
func makeCoordinator() -> SearchBarController.Coordinator {
return Coordinator(text: $text)
}
}
I present a view in a sheet that consists of a navigation stack and a scroll view which has a photo pushed to the top by setting .ignoresSafeArea(edges: .top). The problem is the top of the photo is blurry due to the scroll edge effect. I would like to hide the scroll edge effect so the photo is fully visible when scrolled to the top but let the effect become visible upon scrolling down. Is that possible?
struct ContentView: View {
@State private var showingSheet = false
var body: some View {
VStack {
Button("Present Sheet") {
showingSheet = true
}
}
.sheet(isPresented: $showingSheet) {
SheetView()
}
}
}
struct SheetView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
ScrollView {
VStack {
Image("Photo")
.resizable()
.scaledToFill()
}
}
.ignoresSafeArea(edges: .top)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(role: .close) {
dismiss()
}
}
ToolbarItem {
EditButton()
}
}
}
}
}
Starting on iOS 26 Beta 3, any UIVisualEffectView using a UIGlassEffect will have a default corner radius that cannot be modified by using UIVisualEffectView's layer.cornerRadius. This was working on Beta 1 and Beta 2.
On WWDC25 "Build a UIKit app with the new design", a UIVisualEffectView property called cornerConfiguration is used as example for changing the effect's corner radius, but this property does not seem to be available on any of the beta versions.
Is there any other way to update the UIGlassEffect corner radius on UIKit?
Hi,
In iOS 26, pushing or popping a view controller via UINavigationController shows a rounded corner effect during transition. This seems to be a new system feature.
Is there a way to disable this and restore the previous full-rectangle style, as seen in earlier iOS versions (e.g. iOS 18)? Any official API or recommended approach?
Thanks!
Hello Developer Forums Team,
I’ve seen that some banking apps prevent screenshots on certain sensitive screens. I’m working on a similar feature in my SDK and want to confirm if my implementation complies with App Store guidelines.
Since there’s no public API to block screenshots, I’m using a workaround based on the secure rendering behavior of UITextField (isSecureTextEntry = true). I embed my custom content (e.g., a UITableView) inside the internal secure container of a UITextField, which results in blank content being captured during screenshots—similar to what some banking apps do.
Approach Summary
I create a UITextField
I detect its internal secure container by matching UIKit internal class names as strings
I embed my real UI content into that container
I do not use or call any private APIs, just match view class names via strings.
ScreenshotPreventingView.swift
final class ScreenshotPreventingView: UIView {
private let textField = UITextField()
private let recognizer = HiddenContainerRecognizer()
private var contentView: UIView?
public var preventScreenCapture = true {
didSet {
textField.isSecureTextEntry = preventScreenCapture
}
}
public init(contentView: UIView? = nil) {
super.init(frame: .zero)
self.contentView = contentView
setupUI()
}
private func setupUI() {
guard let container = try? recognizer.getHiddenContainer(from: textField) else { return }
addSubview(container)
NSLayoutConstraint.activate([
container.topAnchor.constraint(equalTo: topAnchor),
container.bottomAnchor.constraint(equalTo: bottomAnchor),
container.leadingAnchor.constraint(equalTo: leadingAnchor),
container.trailingAnchor.constraint(equalTo: trailingAnchor)
])
if let contentView = contentView {
setup(contentView: contentView, in: container)
}
DispatchQueue.main.async {
self.preventScreenCapture = true
}
}
private func setup(contentView: UIView) {
self.contentView?.removeFromSuperview()
self.contentView = contentView
guard let container = hiddenContentContainer else { return }
container.addSubview(contentView)
container.isUserInteractionEnabled = isUserInteractionEnabled
contentView.translatesAutoresizingMaskIntoConstraints = false
let bottomConstraint = contentView.bottomAnchor.constraint(equalTo: container.bottomAnchor)
bottomConstraint.priority = .required - 1
NSLayoutConstraint.activate([
contentView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: container.trailingAnchor),
contentView.topAnchor.constraint(equalTo: container.topAnchor),
bottomConstraint
])
}
}
HiddenContainerRecognizer.swift
struct HiddenContainerRecognizer {
private enum Error: Swift.Error {
case unsupportedOSVersion(version: Float)
case desiredContainerNotFound(_ containerName: String)
}
func getHiddenContainer(from view: UIView) throws -> UIView {
let containerName = try getHiddenContainerTypeInStringRepresentation()
let containers = view.subviews.filter { subview in
type(of: subview).description() == containerName
}
guard let container = containers.first else {
throw Error.desiredContainerNotFound(containerName)
}
return container
}
private func getHiddenContainerTypeInStringRepresentation() throws -> String {
if #available(iOS 15, *) {
return "_UITextLayoutCanvasView"
}
if #available(iOS 14, *) {
return "_UITextFieldCanvasView"
}
if #available(iOS 13, *) {
return "_UITextFieldCanvasView"
}
if #available(iOS 12, *) {
return "_UITextFieldContentView"
}
let currentIOSVersion = (UIDevice.current.systemVersion as NSString).floatValue
throw Error.unsupportedOSVersion(version: currentIOSVersion)
}
}
How I use it in my Screen
let container = ScreenshotPreventingView()
override func viewDidLoad() {
super.viewDidLoad()
container.preventScreenCapture = true
container.setup(contentView: viewContainer) //viewContainer is UIView in storyboard, in which all other UI elements are placed in e.g. UITableView
self.view.addSubview(container)
container.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
container.topAnchor.constraint(equalTo: self.view.topAnchor),
container.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
container.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
container.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
}
What I’d Like to Confirm
Is this approach acceptable for App Store submission?
Is there a more Apple-recommended approach to prevent screen capture of arbitrary UI?
Thank you for your help in ensuring compliance.
Hello Apple Developer Community: I have a problem with the fullscreencover. I can see the Things, that shouldn’t be visible behind it.
I’m currently developing with iOS 26 and only there it happens.
I hope you can help me :)
Have a nice day
Hi Apple Developer Team,
I'm encountering a regression in iOS 18 related to the Picture-in-Picture (PiP) feature when using custom views.
In previous versions of iOS (up to iOS 17), it's possible to show a custom UIView inside the PiP window — for example, a UILabel, UITableView, or other standard UI elements. This works well even when switching between apps.
However, in iOS 18 (tested on the developer beta), there's an issue:
If App A starts PiP mode and displays a custom view, and then the user switches to App B and starts a video call (e.g., using FaceTime or another VoIP app), all the custom views in the PiP window suddenly disappear. The PiP window itself remains, but its contents are empty. This behavior did not occur in earlier iOS versions.
Steps to reproduce:
In App A, start Picture-in-Picture with a custom UIView added to the PiP window.
Switch to App B and initiate a video call (e.g., FaceTime).
Observe the PiP window — the custom view is no longer visible.
This issue breaks UI functionality that previously worked and may impact apps that rely on interactive or dynamic content in PiP.
Is this a known issue in iOS 18, or is this behavior change intentional? Any suggested workarounds or updates?
Thanks in advance for your support.
In my application, I have NavigationStack presented as a sheet, and I intend to dynamically adjust its height while pushing views within it. I'm utilizing a global observable variable to manage the height and everything works fine except that the height changes abruptly without any animation. It abruptly transitions from one height to another.
The issue can be reproduced using the following code:
#Preview {
@Previewable @State var height: CGFloat = 200
Text("Parent View")
.sheet(isPresented: .constant(true)) {
NavigationStack {
Form {
NavigationLink("Button") {
RoundedRectangle(cornerRadius: 20)
.fill(Color.blue)
.frame(height: 200)
.navigationTitle("Child")
.onAppear {
withAnimation {
height = 300
}
}
}
}
.navigationTitle("Parent")
.navigationBarTitleDisplayMode(.inline)
.presentationDetents([.height(height)])
.onAppear {
withAnimation {
height = 150
}
}
}
}
}
Right now, the traffic light buttons overlapped on my iPad app top corner on windows mode (full screen is fine).
How do I properly design my app to avoid the traffic light buttons? Detect that it is iPadOS 26?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I have installed the iOS 26 Beta on my device and conducted a comprehensive functionality test of my iOS application, which I designed and developed. The application includes a feature that allows users to share images directly to X (formerly Twitter) and Facebook.
During testing, I encountered an issue where the icons for X (formerly Twitter) and Facebook do not appear in the share dialog, despite both apps being installed on the device. This issue prevents users from sharing images to these platforms directly from the app.
Steps to Reproduce:
1.Install iOS 26 Beta on a compatible device.
2.Ensure that both the X (formerly Twitter) and Facebook apps are installed and logged in on the device.
3.Open the iOS application and navigate to the image sharing feature.
4.Attempt to share an image using the share dialog.
5.Observe that the icons for X (formerly Twitter) and Facebook are missing from the share options.
Expected Behavior:
The share dialog should display icons for X (formerly Twitter) and Facebook, allowing users to share images directly to these platforms.
Actual Behavior:
The icons for X (formerly Twitter) and Facebook do not appear in the share dialog, preventing direct sharing to these platforms.
Code Implementation:
I have not implemented any code to exclude X (formerly Twitter) and Facebook from the share options. Below is the relevant code for controlling the share screen:
let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
let excludedTypes = [
UIActivity.ActivityType.assignToContact,
UIActivity.ActivityType.print,
]
activityViewController.excludedActivityTypes = excludedTypes
activityViewController.completionWithItemsHandler = completion
self.present(activityViewController, animated: true, completion: nil)
As shown in the implementation, there is no exclusion of X (formerly Twitter) and Facebook, yet their icons do not appear in the share dialog.
With the new multi-windowing design in iPadOS 26, the behavior of openWindow() has changed.
In iPadOS 18, if I called openWindow(), I would go from a full-screen window to two side-by-side windows. That allowed my app to meet the goal of the user; keep some information on the screen while being able to navigate through the app in the other window.
In iPadOS 26 (beta 3), this no longer works. Instead, a new Window opens ON top of the current window. I am looking for some mechanism to help the user see that two windows are now present and then easily move them on the screen (tiled, side-by-side) or whatever else they would prefer.
iOS 26 seems to have changed the way action extension icons appear in the share sheet. My icon is too small now compared to the Copy button in Safari (and Shortcuts’ icons are too small too, a bug?). How do you update it, and how do you ensure it looks fine in iOS 18 and earlier?
My current icon is an AppIcon in the asset catalog, single size 1024x1024, with about 130px padding around it.
I am using XCODE-BETA (Version 26.0 beta (17A5241e)) on a Mac (running Sequoia 15.5) to develop an app using FoundationModel. I am testing on an iPad (iPad Pro 11 in, 2nd Gen, running iPadOS 26 Beta 3).
My app works fine when I run it in the simulator (iPad 26.0).
So I upgraded my iPad Pro to iPadOS 26 beta 3 to try it on a real device.
When I run it on the device, I get an error about symbols not found. [See details below]
Any idea what I need to change in my development configuration to allow me to run/test my app on a real device running iPadOS 26 beta 3?
Thanks in advance,
Charlie
dyld[1132]: Symbol not found: _$s6WebKit0A4PageC4loadyAC12NavigationIDVSg10Foundation10URLRequestVF
Referenced from: <65E40738-6E3A-3F65-B39F-9FD9A695763C> /private/var/containers/Bundle/Application/34F9D5CE-3E54-4312-8574-10B506C713FA/Blossom.app/Blossom.debug.dylib
Expected in: /System/Library/Frameworks/WebKit.framework/WebKit
Symbol not found: _$s6WebKit0A4PageC4loadyAC12NavigationIDVSg10Foundation10URLRequestVF
Referenced from: <65E40738-6E3A-3F65-B39F-9FD9A695763C> /private/var/containers/Bundle/Application/34F9D5CE-3E54-4312-8574-10B506C713FA/Blossom.app/Blossom.debug.dylib
Expected in: /System/Library/Frameworks/WebKit.framework/WebKit
dyld config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/usr/lib/libLogRedirect.dylib:/usr/lib/libBacktraceRecording.dylib:/usr/lib/libMainThreadChecker.dylib:/usr/lib/libRPAC.dylib:/usr/lib/libViewDebuggerSupport.dylib
Symbol not found: _$s6WebKit0A4PageC4loadyAC12NavigationIDVSg10Foundation10URLRequestVF
Referenced from: <65E40738-6E3A-3F65-B39F-9FD9A695763C> /private/var/containers/Bundle/Application/34F9D5CE-3E54-4312-8574-10B506C713FA/Blossom.app/Blossom.debug.dylib
Expected in: /System/Library/Frameworks/WebKit.framework/WebKit
dyld config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/usr/lib/libLogRedirect.dylib:/usr/lib/libBacktraceRecording.dylib:/usr/lib/libMainThreadChecker.dylib:/usr/lib/libRPAC.dylib:/usr/lib/libViewDebuggerSupport.dylib
I'm using UIViewControllerAnimatedTransitioning to customize my view controllers transitions. When I push a viewcontroller on my navigation stack I need to have a fade in/out instead of the standard right-to-left transition. But having this code appears to break the liquid glass nav-bar buttons morphing from one screen to another.
Is there a way to keep these nice morphing and still have the a custom view controller transitions?
Is there any way to change the color of default items like Back button or Search?
Even if I apply .tint() to a view these items in the .toolbar are always in primary color.
Code that reproduces the issue
import SwiftUI
@main
struct KeyboardLayoutProblemApp: App {
var body: some Scene {
WindowGroup {
iOSTabView()
}
}
}
struct iOSTabView: View {
var body: some View {
TabView {
GameView()
.frame(maxWidth: UIScreen.main.bounds.width, maxHeight: UIScreen.main.bounds.height)
.tabItem {
Label("Play", systemImage: "gamecontroller.fill")
}
}
}
}
struct GameView: View {
var body: some View {
VStack {
Text("Play")
Spacer()
KeyboardView()
}
.padding()
}
}
struct KeyboardView: View {
let firstRowLetters = "qwertyuiop".map { $0 }
let secondRowLetters = "asdfghjkl".map { $0 }
let thirdRowLetters = "zxcvbnm".map { $0 }
var body: some View {
VStack {
HStack {
ForEach(firstRowLetters, id: \.self) {
LetterKeyView(character: $0)
}
}
HStack {
ForEach(secondRowLetters, id: \.self) {
LetterKeyView(character: $0)
}
}
HStack {
ForEach(thirdRowLetters, id: \.self) {
LetterKeyView(character: $0)
}
}
}
.padding()
}
}
struct LetterKeyView: View {
let character: Character
var width: CGFloat { height*0.8 }
@ScaledMetric(relativeTo: .title3) private var height = 35
var body: some View {
Button {
print("\(character) pressed")
} label: {
Text(String(character).capitalized)
.font(.title3)
.frame(width: self.width, height: self.height)
.background {
RoundedRectangle(cornerRadius: min(width, height)/4, style: .continuous)
.stroke(.gray)
}
}
.buttonStyle(PlainButtonStyle())
}
}
Problem
GameView doesn't fit its parent view:
Question
How do I make GameView be at most as big as its parent view?
What I've tried and didn't work
GameView()
.frame(maxWidth: .infinity, maxHeight: .infinity)
GeometryReader { geometry in
GameView()
.frame(maxWidth: geometry.size.width, maxHeight: geometry.size.height)
}
GameView()
.clipped()
GameView()
.layoutPriority(1)
GameView()
.scaledToFit()
GameView()
.minimumScaleFactor(0.01)
GameView()
.scaledToFill()
.minimumScaleFactor(0.5)
I'm not using UIScreen.main.bounds.width because I'm trying to build a multi-platform app.
Topic:
UI Frameworks
SubTopic:
SwiftUI