Hi everyone,
I’m building an iOS app that originally targeted iPhone using NavigationStack. Now I’m adapting it for iPad and switched to using NavigationSplitView to support a three-column layout.
The structure looks like this:
NavigationSplitView {
A // Sidebar
} content: {
B // Middle column – this shows a list
} detail: {
C // Detail view
}
The issue is with the list shown in view B (the content column). It appears completely unstyled, as if it’s using .listStyle(.plain) — with no background material, and a very flat look.
I can understand that this might be intentional on iPad to visually distinguish the three columns.
However, the problem is that this same unstyled list also appears on iPhone, even though iPhone only shows a single column view at a time!
I tried explicitly setting .listStyle(.insetGrouped) or .listStyle(.grouped) on the list in view B, but it makes no difference.
When I go back to NavigationStack, the list in B is styled properly, just as expected — but then I lose the enhanced iPad layout.
What I’m looking for:
I’d like to keep using NavigationSplitView, but I want the list in the content column (view B) to use the default iOS list styling, at least on iPhone.
Is there any way to achieve this?
Thanks!
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi everyone,
I’m building an iOS app that originally targeted iPhone using NavigationStack. Now I’m adapting it for iPad and switched to using NavigationSplitView to support a three-column layout.
The structure looks like this:
NavigationSplitView {
A // Sidebar
} content: {
B // Middle column – this shows a list
} detail: {
C // Detail view
}
The issue is with the list shown in view B (the content column). It appears completely unstyled, as if it’s using .listStyle(.plain) — with no background material, no grouped sections, and a very flat look.
I can understand that this might be intentional on iPad to visually distinguish the three columns.
However, the problem is that this same unstyled list also appears on iPhone, even though iPhone only shows a single column view at a time!
I tried explicitly setting .listStyle(.insetGrouped) or .listStyle(.grouped) on the list in view B, but it makes no difference.
When I go back to NavigationStack, the list in B is styled properly, just as expected — but then I lose the enhanced iPad layout.
What I’m looking for:
I’d like to keep using NavigationSplitView, but I want the list in the content column (view B) to use the default iOS list styling, at least on iPhone.
Is there any way to achieve this?
Thanks!
Hi everyone,
I’m trying to recreate the beautiful transition effect used in Apple’s built-in Calendar app — specifically the one where, when you tap on a month, you’re “pulled into” the next view, and when going from month to day, the views seem to slide vertically, almost as if one is pushing the other off-screen. It’s not the standard right-to-left slide you get with NavigationStack or NavigationLink, and it feels much more immersive and dynamic.
I’ve been experimenting with .matchedGeometryEffect and .transition(.move(...)) in a ZStack, and while I can replicate some aspects, I’m still missing that fluid, directional pull that makes it feel like you’re diving deeper into the calendar. I’m also unsure how much the view structure between the source and destination needs to match for the matchedGeometryEffect to really shine.
Does anyone know what APIs or techniques Apple might be using internally to build that kind of animation? Is there a clean way to achieve something similar using SwiftUI as of iOS 17 or 18? Would love to hear if someone here has successfully replicated this or has tips on best practices.
Thanks in advance!
Topic:
UI Frameworks
SubTopic:
SwiftUI
Using SwiftUI on macOS, how can I add a toolbar item on the right-most (trailing) edge of the window's toolbar when an Inspector is used?
At the moment, the toolbar items are all left-of (leading) the split view tracking separator. I want the inspector toolbar item to be placed similar to where Xcode's Inspector toolbar item is placed: always as far right (trailing) as possible.
NavigationSplitView {
// ... snip
} detail: {
// ... snip
}
.inspector(isPresented: $isInspectorPresented) {
InspectorContentView()
}
.toolbar {
// What is the correct placement value here?
ToolbarItem(placement: .primaryAction) {
Button {
isInspectorPresented.toggle()
} label: {
Label("Toggle Inspector", systemImage: "sidebar.trailing")
}
}
}
See the attached screenshot. When the InspectorView is toggled open, the toolbar item tracks leading the split view tracking separator, which is not consistent with how Xcode works.
(Also submitted as FB19359821)
I suggest a PresentationDetent.sizeToFit or PresentationDetent.contentSize that automatically sizes the sheet to the height of the contained Views.
This seems to be a common requirement for many app developers and it would be nice if this would be supported out of the box without fiddling around with the usual GeometryReader in background -> make available the height with a preference key -> .presentationDetents([.height(…)]) workarounds.
Topic:
UI Frameworks
SubTopic:
SwiftUI
My app uses VStack and HStack, instead of the normal table format. When I try to print everything works perfect but it will not print the cell outline.
What is the correct line code or instruction terminology?
Thanks, Hal
MultiTasking >> how to disable multitasking window in code level on IpadOS 26.0 Beta
Is there a way in app level we can disable multitasking window? force full-screen mode on iPad via API.
Topic:
UI Frameworks
SubTopic:
SwiftUI
When a ScrollView or List is nested in a TabView, you can press on the tab button and the scroll view will scroll to top.
import SwiftUI
struct SwiftUIView: View {
let items = (1...100).map { "Item \($0)" }
var body: some View {
TabView {
Tab("home", systemImage: "house") {
ScrollView {
ForEach(items, id: \.self) { item in
Text(item)
.frame(maxWidth: .infinity, alignment: .center)
}
}
}
}
}
}
#Preview {
SwiftUIView()
}
But if we add a background to the ScrollView, the scroll to top gesture breaks.
import SwiftUI
struct SwiftUIView: View {
let items = (1...100).map { "Item \($0)" }
var body: some View {
TabView {
Tab("home", systemImage: "house") {
ScrollView {
ForEach(items, id: \.self) { item in
Text(item)
.frame(maxWidth: .infinity, alignment: .center)
}
}
// Set background on ScrollView.
.background(Color.red)
}
}
}
}
#Preview {
SwiftUIView()
}
I made a similar post on StackOverflow, but haven't been able to find a proper solution.
This feels like a bug of some sort in SwiftUI.
The first-party Apple Translate app will switch the on-screen keyboard to the selected language, even when the keyboard for that language is NOT added in Settings > General > Keyboards.
We'd like to mirror this behavior and switch the keyboard for input based on a user-selected language from a drop-down without the user needing to add that language to Keyboards
I'm struggling to find if this behavior is achieved via a public API. Any insights here?
Is there a way to constrain the AttributedTextFormattingDefinition of a TextEditor to only bold/italic/underline/strikethrough, without showing the full Font UI?
struct CustomFormattingDefinition: AttributedTextFormattingDefinition {
struct Scope: AttributeScope {
let font: AttributeScopes.SwiftUIAttributes.FontAttribute
let underlineStyle: AttributeScopes.SwiftUIAttributes.UnderlineStyleAttribute
let strikethroughStyle: AttributeScopes.SwiftUIAttributes.StrikethroughStyleAttribute
}
var body: some AttributedTextFormattingDefinition<Scope> {
ValueConstraint(for: \.font,
values: [MyStyle.defaultFont, MyStyle.boldFont, MyStyle.italicFont, MyStyle.boldItalicFont],
default: MyStyle.defaultFont)
ValueConstraint(for: \.underlineStyle,
values: [nil, .single],
default: .single)
ValueConstraint(for: \.strikethroughStyle,
values: [nil, .single],
default: .single)
}
}
If I remove the Font attribute from the scope, the Bold and Italic buttons disappear. And if the Font attribute is defined, even if it's restricted to one typeface in 4 different styles, the full typography UI is displayed.
Pseudo-code:
PhaseAnimator([false,true], trigger: foo) { flash in
ZStack {
Capsule()
.foregroundStyle(flash ? .red : .green)
Canvas { context, size in
context.draw(image: Image(name: "foo"), toFitRect: some_rectangle);
context.draw(text: Text("foo"), toFitRect: another_rectangle);
}
.foregroundStyle(flash ? .black : .white)
}
} animation: { flash in
return .linear(duration: 0.5);
}
The Capsule's colour animates, but the Canvas's doesn't. The Canvas drawing code is only ever called with flash==false.
What do I have to do to the Canvas so that it redraws with the intermediate colours during the animation?
Because .searchable does not allow for customizing buttons in the search bar, I've manually had to recreate the search bar as shown below. However, when removing one of the items in the search bar, the TextField does not resize correctly and effectively inserts padding on the leading edge. When the TextField is focused, it resizes and fills the entire space. If the "Compose" button was already hidden when the search bar is presented, it lays out correctly. How do I resize the TextField after removing the "Compose" button automatically?
Thanks, jjp
struct ContentView: View {
@State var isSearchBarVisible = false
@State var isComposingMessage = false
@State var searchText = ""
let items: [String] = ["hey", "there", "how", "are", "you"]
var searchItems: [String] {
items.filter { item in
item.lowercased().contains(searchText.lowercased())
}
}
var body: some View {
NavigationStack {
VStack {
List {
if !searchText.isEmpty {
ForEach(searchItems, id: \.self) { item in
Text(item)
}
} else {
ForEach(items, id: \.self) { item in
Text(item)
}
}
}
}
.toolbar {
if isSearchBarVisible {
ToolbarItem(placement: .principal) {
TextField("Search", text: $searchText)
.padding(8)
.background(Color.gray.opacity(0.2))
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
isSearchBarVisible = false
},[![enter image description here][1]][1]
label: {
Text("Cancel")
})
}
if !isComposingMessage {
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
isComposingMessage.toggle()
},
label: {
Text("Compose")
})
}
}
}
else {
ToolbarItem(placement: .topBarLeading) {
Button(action: {
isSearchBarVisible = true
},
label: {
Text("Search")
})
}
ToolbarItem(placement: .principal) {
Text("Title")
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
isComposingMessage.toggle()
},
label: {
Text("Compose")
})
}
}
}
}
}
}
Summary
When a SwiftUI widget uses a Link containing an Image modified with .widgetAccentedRenderingMode (using any mode except .fullColor), tapping the image on the widget launches the app but does not pass the expected deep link URL to the SceneDelegate.
Steps to Reproduce
Create a SwiftUI Widget View with a Link:
struct ImageView: View {
var image: UIImage
var body: some View {
Link(URL(string: "myapp://image")!) {
Image(uiImage: image)
.resizable()
.widgetAccentedRenderingMode(.accentedDesaturated) // or any mode other than .fullColor
.scaledToFill()
.clipped()
}
}
}
Add Custom URL Scheme in Info.plist:
<dict>
<key>CFBundleURLName</key>
<string>com.company.myapp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
Implement Deep Link Handling in SceneDelegate:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let url = connectionOptions.urlContexts.first?.url {
handle(url)
}
}
func scene(_ scene: UIScene, openURLContexts urlContexts: Set<UIOpenURLContext>) {
if let url = urlContexts.first?.url {
handle(url)
}
}
private func handle(_ url: URL) {
// Process URL here
}
Run the application on a device or simulator.
Add the widget to the Home Screen.
Tap the image inside the widget.
Expected Result
The application launches and receives the URL in SceneDelegate, as expected.
Actual Result
The application launches, but the URL is not passed to SceneDelegate.
Both connectionOptions.urlContexts and openURLContexts are empty.
We've been trying to track down a non-reproducible issue for the past few months, and I'm wondering if anybody has encountered the same one.
Screenshots of the issue attached here. As you can see, the toolbar isn't respecting the safe area; there are many more issues that occur when this bug happens as well, such as the app being extremely laggy and sheets not opening.
Anecdotally, this seems to happen if the app is opened after not having been opened in a while (say, a day or so). It tends to happen first thing in the morning when I open the app, but as I mentioned, it's been very hard to reproduce.
I'm also wondering if it's a known SwiftUI navigation issue or if anyone has encountered this.
SwiftUI.List allows for customization using .listItemTint, .tint, or .foregroundStyle. This can be used to color individual items in the list, other than the app's specified accent color.
Is there an equivalent feature to customize individual Tab's icon or label, when using TabView's SidebarAdaptableTabViewStyle, and its in the sidebar style.
From what I understand, there needs to be a modifier applied directly to Tab unlike List, and not just the label.
Since there isn't any color/tint modifiers, is it not possible?
My SwiftUI code runs fine on macOS, iOS(iPad) and larger iPhones, but will not display the detail view on smaller iPhones.
Is there a way to force the smaller iPhones to display the detail view?
And if not,
When I put the App on the Apple store, for sale, will the Apple store be smart enough to flag the App as not appropriate for smaller iPhones, such as the SE (2nd and 3rd gen.) and prevent downloads?
Thanks in advance for any guidance.
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)
}
}
Hi,
My app has an IAP and the view that let user to purchase is simply a ProductView. The purchase flow should be handled by the ProductView itself. I have tested the app with xcode storekit configuration, xcode run with sandbox account and also TestFlight environment as well. The purchase is triggered and the app feature is unlocked after purchase. However, I keep getting app review team feedback with the following problem:
Bug description: the purchase button is greyed out after we tapped on it, however, there's no purchase flow popped up
I have tried multiple things. Building with xcode cloud, removing the storekit configuration from the build scheme. But none can get the app review team to get through the problem.
The IAP is not available in certain region. In that case, the app will show a message. However, the app review attached an screenshot which shows the product view.
The view that allow users to purchase
if let product = store.products.first(where: { $0.id == "com.xxx.xxxxxxx" }) {
// If the product is available, show the ProductView
ProductView(id: product.id)
.productViewStyle(.compact)
} else {
// If the product is not available, show a message
Text("In-app purchase is not available in your region.")
}
The store class
@Published private(set) var products: [Product] = []
...
init() {
//To handle the parental approval flow
getUpdateTransaction()
}
func getUpdateTransaction() {
updates = Task {
for await update in StoreKit.Transaction.updates {
if let transaction = try? update.payloadValue {
await fetchActiveTransactions()
await transaction.finish()
}
}
}
}
Does anyone what can go wrong with ProductView? As this is part of the StoreKit API, I don't know what can go wrong. At least the purchase flow should be covered by it.
Also, is sandbox and TestFlight a good way to test IAP?
Thanks!
During the WWDC Session called "Design widgets for visionOS" the presenter says:
You can choose whether the background of your widget participates in tinting. If you opted out, for example to preserve a photo or illustration, make sure it still looks good alongside the selected color palette.
https://developer.apple.com/videos/play/wwdc2025/255
Unfortunately, this session has no example code. Can someone point me to the correct way to do this? Is there a modifier we can use on views?
When a user selects one the tint colors using the configuration screen, we would like to prevent some views from being tinted.
In our app we have a view with a custom scroll implementation in a TabView. We would like to programmatically minimize (not hide) the TabView, like .tabBarMinimizeBehavior(...) does when a List is behind the tab bar and a user scrolls. I haven't found any view modifier that I can attach that allows me to do so, is this not possible? I would have expected something like
.tabBarMinimized($tabBarMinimized)
Topic:
UI Frameworks
SubTopic:
SwiftUI