Create elegant and intuitive apps that integrate seamlessly with Apple platforms.

All subtopics
Posts under Design topic

Post

Replies

Boosts

Views

Activity

Using @Environment for a router implementation...
Been messing with this for a while... And cannot figure things out... Have a basic router implemented... import Foundation import SwiftUI enum Route: Hashable { case profile(userID: String) case settings case someList case detail(id: String) } @Observable class Router { var path = NavigationPath() private var destinations: [Route] = [] var currentDestination: Route? { destinations.last } var navigationHistory: [Route] { destinations } func navigate(to destination: Route) { destinations.append(destination) path.append(destination) } } And have gotten this to work with very basic views as below... import SwiftUI struct ContentView: View { @State private var router = Router() var body: some View { NavigationStack(path: $router.path) { VStack { Button("Go to Profile") { router.navigate(to: .profile(userID: "user123")) } Button("Go to Settings") { router.navigate(to: .settings) } Button("Go to Listings") { router.navigate(to: .someList) } .navigationDestination(for: Route.self) { destination in destinationView(for: destination) } } } .environment(router) } @ViewBuilder private func destinationView(for destination: Route) -> some View { switch destination { case .profile(let userID): ProfileView(userID: userID) case .settings: SettingsView() case .someList: SomeListofItemsView() case .detail(id: let id): ItemDetailView(id: id) } } } #Preview { ContentView() } I then have other views named ProfileView, SettingsView, SomeListofItemsView, and ItemDetailView.... Navigation works AWESOME from ContentView. Expanding this to SomeListofItemsView works as well... Allowing navigation to ItemDetailView, with one problem... I cannot figure out how to inject the Canvas with a router instance from the environment, so it will preview properly... (No idea if I said this correctly, but hopefully you know what I mean) import SwiftUI struct SomeListofItemsView: View { @Environment(Router.self) private var router var body: some View { VStack { Text("Some List of Items View") Button("Go to Item Details") { router.navigate(to: .detail(id: "Test Item from List")) } } } } //#Preview { // SomeListofItemsView() //} As you can see, the Preview is commented out. I know I need some sort of ".environment" added somewhere, but am hitting a wall on figuring out exactly how to do this. Everything works great starting from contentview (with the canvas)... previewing every screen you navigate to and such, but you cannot preview the List view directly. I am using this in a few other programs, but just getting frustrated not having the Canvas available to me to fine tune things... Especially when using navigation on almost all views... Any help would be appreciated.
2
0
269
Jul ’25
SwiftData and discarding unsaved changes idea???
Someone smarter than me please tell me if this will work... I want to have an edit screen for a SwiftData class. Auto Save is on, but I want to be able to revert changes. I have read all about sending a copy in, sending an ID and creating a new context without autosave, etc. What about simply creating a second set of ephemeral values in the actual original model. initialize them with the actual fields. Edit them and if you save changes, migrate that back to the permanent fields before returning. Don't have to manage a list of @State variables corresponding to every model field, and don't have to worry about a second model context. Anyone have any idea of the memory / performance implications of doing it this way, and if it is even possible? Does this just make a not quite simple situation even more complicated? Haven't tried yet, just got inspiration from reading some medium content on attributes on my lunch break, and wondering if I am just silly for considering it.
2
0
179
Jul ’25
Multi-Selection List : changing Binding Array to Binding Set and back again
I am trying to create a menu picker for two or three text items. Small miracles, but I have it basically working. Problem is it uses a set, and I want to pass arrays. I need to modify PickerView so the Bound Parameter is an [String] instead of Set. Have been fighting this for a while now... Hoping for insights. struct PickerView: View { @Binding var colorChoices: Set<String> let defaults = UserDefaults.standard var body: some View { let possibleColors = defaults.object(forKey: "ColorChoices") as? [String] ?? [String]() Menu { ForEach(possibleColors, id: \.self) { item in Button(action: { if colorChoices.contains(item) { colorChoices.remove(item) } else { colorChoices.insert(item) } }) { HStack { Text(item) Spacer() if colorChoices.contains(item) { Image(systemName: "checkmark") } } } } } label: { Label("Select Items", systemImage: "ellipsis.circle") } Text("Selected Colors: \(colorChoices, format: .list(type: .and))") } } #Preview("empty") { @Previewable @State var colorChoices: Set<String> = [] PickerView(colorChoices: $colorChoices) } #Preview("Prefilled") { @Previewable @State var colorChoices: Set<String> = ["Red","Blue"] PickerView(colorChoices: $colorChoices) } My Content View is suppose to set default values the first time it runs, if no values already exist... import SwiftUI struct ContentView: View { @State private var viewDidLoad: Bool = false var body: some View { HomeView() .onAppear { // The following code should execute once the first time contentview loads. If a user navigates back to it, it should not execute a second time. if viewDidLoad == false { viewDidLoad = true // load user defaults let defaults = UserDefaults.standard // set the default list of school colors, unless the user has already updated it prior let defaultColorChoices: [String] = ["Black","Gold","Blue","Red","Green","White"] let colorChoices = defaults.object(forKey: "ColorChoices") as? [String] ?? defaultColorChoices defaults.set(colorChoices, forKey: "ColorChoices") } } } } #Preview { ContentView() } PickLoader allows you to dynamically add or delete choices from the list... import SwiftUI struct PickLoader: View { @State private var newColor: String = "" var body: some View { Form { Section("Active Color Choices") { // we should have set a default color list in contentview, so empty string should not be possible. let defaults = UserDefaults.standard let colorChoices = defaults.object(forKey: "ColorChoices") as? [String] ?? [String]() List { ForEach(colorChoices, id: \.self) { color in Text(color) } .onDelete(perform: delete) HStack { TextField("Add a color", text: $newColor) Button("Add"){ defaults.set(colorChoices + [newColor], forKey: "ColorChoices") newColor = "" } } } } } .navigationTitle("Load Picker") Button("Reset Default Choices") { let defaults = UserDefaults.standard //UserDefaults.standard.removeObject(forKey: "ColorChoices") let colorChoices: [String] = ["Black","Gold","Blue","Red","Green","White"] defaults.set(colorChoices, forKey: "ColorChoices") } Button("Clear all choices") { let defaults = UserDefaults.standard defaults.removeObject(forKey: "ColorChoices") } } } func delete(at offsets: IndexSet) { let defaults = UserDefaults.standard var colorChoices = defaults.object(forKey: "ColorChoices") as? [String] ?? [String]() colorChoices.remove(atOffsets: offsets) defaults.set(colorChoices, forKey: "ColorChoices") } #Preview { PickLoader() } And finally HomeView is where I am testing from - to see if binding works properly... import SwiftUI struct HomeView: View { //@State private var selection: Set<String> = [] //@State private var selection: Set<String> = ["Blue"] @State private var selection: Set<String> = ["Blue", "Red"] var body: some View { NavigationStack { List { Section("Edit Picker") { NavigationLink("Load Picker") { PickLoader() } } Section("Test Picker") { PickerView(colorChoices: $selection) } Section("Current Results") { Text("Current Selection: \(selection, format: .list(type: .and))") } } .navigationBarTitle("Hello, World!") } } } #Preview { HomeView() } If anyone uses this code, there are still issues - buttons on Loader don't update the list on the screen for one, and also dealing with deleting choices that are in use - how does picker deal with them? Probably simply add to the list automatically and move on. If anyone has insights on any of this also, great! but first I just need to understand how to accept an array instead of a set in pickerView. I have tried using a computed value with a get and set, but I can't seem to get it right. Thanks for any assistance! Cheers!
2
0
187
Jul ’25
Liquid Glass clear variant isn't clear
I've been experimenting with Liquid Glass quite a bit and watched all the WWDC videos. I'm trying to create a glassy segmented picker, like the one used in Camera: however, it seems that no matter what I do there's no way to recreate a truly clear (passthrough) bubble that just warps the light underneath around the edges. Both Glass.regular and Glass.clear seem to add a blur that can not be evaded, which is counter to what clear ought to mean. Here are my results: I've used SwiftUI for my experiment but I went through the UIKit APIs and there doesn't seem to be anything that suggests full transparency. Here is my test SwiftUI code: struct GlassPicker: View { @State private var selected: Int? var body: some View { ScrollView([.horizontal], showsIndicators: false) { HStack(spacing: 0) { ForEach(0..<20) { i in Text("Row \(i)") .id(i) .padding() } } .scrollTargetLayout() } .contentMargins(.horizontal, 161) .scrollTargetBehavior(.viewAligned) .scrollPosition(id: $selected, anchor: .center) .background(.foreground.opacity(0.2)) .clipShape(.capsule) .overlay { DefaultGlassEffectShape() .fill(.clear) // Removes a semi-transparent foreground fill .frame(width: 110, height: 50) .glassEffect(.clear) } } } Is there any way to achieve the above result or does Apple not trust us devs with more granular control over these liquid glass elements?
2
3
147
Aug ’25
iOS 26 Liquid Glass not showing
I’m not seeing Liquid Glass on any standard components. A month ago around July 17th I ran our app and saw Liquid Glass on our tab view and various standard components. Those components have not been changed and yet I’m no longer seeing Liquid Glass in our app at all. Components that were previously liquid glass but now are not include TabView and back navigation buttons. I set the UIDesignRequiresCompatibility key explicitly to false but no luck. I was seeing this in Beta 7 and Beta 8 on a real device and on a sim.
2
1
259
Oct ’25
Clarification on UIDesignRequiresCompatibility Key and Liquid Glass Adoption
Dear Apple Developer Relations Team, We are currently reviewing the documentation for the UIDesignRequiresCompatibility Info.plist key. In the documentation, there is a warning that states: "Temporarily use this key while reviewing and refining your app’s UI for the design in the latest SDKs." However, in the adoption guide for Liquid Glass: Adopting Liquid Glass, we did not see any explicit requirement to force adoption of the Liquid Glass design. We have the Gojek app, which currently uses the UIDesignRequiresCompatibility key. To ensure long-term stability, we would like clarification on the following points: Future Support of the Key: Is it safe to continue using the UIDesignRequiresCompatibility key? Can you confirm whether this key will remain supported or if there are plans for it to be deprecated/removed in future iOS versions? Liquid Glass Adoption: Our app’s design guidelines do not align with the Liquid Glass style. Can you confirm that adoption of Liquid Glass is not mandatory, and that apps can continue to use their existing custom design guidelines without any restrictions? Compatibility with iOS 26: Are there any required changes we need to make to our existing views to ensure that the UI will continue to render as it does today on iOS 26 and beyond? We want to make sure we provide the best user experience while remaining compliant with Apple’s guidelines. Your clarification would help us plan our design and development roadmap accordingly. Thank you for your support and guidance.
Topic: Design SubTopic: General Tags:
2
2
668
Sep ’25
Proposal: Capacitive swipe-based volume control integrated into iPhone frame
I would like to propose a design enhancement for future iPhone models: using the existing bottom-right antenna line (next to the power button area) as a capacitive “volume control zone” that supports swipe gestures. Today this line is a structural antenna break, but it is also located exactly where the thumb naturally rests when holding the phone in one hand. With a small embedded capacitive/force sensor, the user could slide their finger along this zone to control volume without reaching for the physical buttons. Why this makes sense: • Perfect ergonomic thumb position in both portrait and landscape • One-handed volume adjustment becomes easier for large-screen devices • Silent and frictionless vs. clicking buttons (useful in meetings / night mode) • Consistent with Apple’s recent move toward contextual hardware input (Action Button, Capture Button, Vision Pro gestures) The interaction model would be: • Swipe up → increase volume • Swipe down → decrease volume • (Optional) long-press haptic = mute toggle This could also enhance accessibility, especially for users with reduced hand mobility who struggle to press mechanical buttons on tall devices. Technically, this would be similar to the Capture Button (capacitive + pressure layers), but linear instead of pressure-based. It does not replace physical buttons, it complements them as a silent gesture-based alternative. Thank you for considering this as a future interaction refinement for iPhone hardware design.
2
0
529
Oct ’25
Wrong unit in HIG > Components > System Experiences > Widget > watchOS widget dimensions
Hello, I noticed a small mistake in the Human Interface Guidelines (HIG). On the page HIG > Components > System Experiences > Widget > watchOS Widget Dimensions, scroll down to the bottom. In the "watchOS widget dimensions" section, the sizes in the table are in pixels (px), not points (pt) actually. However, the table header indicates the sizes should be in points (pt). Page link: https://developer.apple.com/design/human-interface-guidelines/widgets#watchOS-widget-dimensions For example, the widget size in the Smart Stack on a 49mm watch should be 192x81.5 pt (or 382x163 px), not 382x163 pt. This size can be verified with the information provided here: https://developer.apple.com/documentation/watchos-apps/supporting-multiple-watch-sizes/. https://developer.apple.com/documentation/watchkit/wkinterfacedevice/1620974-screenscale
Topic: Design SubTopic: General Tags:
3
0
834
Jan ’25
AreaMark Always alignsMarkStylesWithPlotArea for linear gradients
I'm trying to make a Swift Chart where 24 AreaMarks an hour apart on X axis over a day display a vertical gradient. The gradient is vertical and is essentially [Color.opacity(0.1),Colour,Color.opacity(0.1] The idea here is where the upper and lower points of each AreaMark are the same or close to each other in the Y axis, the chart essentially displays a line, where they are far apart you get a nice fading vertical gradient. However, it seems that the .alignsMarkStylesWithPlotArea modifier is always set for AreaMarks even if manually applying it false. Investigating further, I've learnt that with AreaMarks in a series, Swift Charts seems to only listen to the first foreground style set in. I've created some sample code to demonstrate this. struct DemoChartView: View { var body: some View { Chart { AreaMark(x: .value("Time", Date().addingTimeInterval(0)), yStart: .value("1", 40), yEnd: .value("2", 60)) .foregroundStyle(LinearGradient(colors: [.pink, .teal], startPoint: .top, endPoint: .bottom)) .alignsMarkStylesWithPlotArea(false) AreaMark(x: .value("Time", Date().addingTimeInterval(3600)), yStart: .value("1", 44), yEnd: .value("2", 58)) .foregroundStyle(LinearGradient(colors: [.orange, .yellow], startPoint: .top, endPoint: .bottom)) .alignsMarkStylesWithPlotArea(false) AreaMark(x: .value("Time", Date().addingTimeInterval(03600*2)), yStart: .value("1", 50), yEnd: .value("2", 90)) .foregroundStyle(LinearGradient(colors: [.green, .blue], startPoint: .top, endPoint: .bottom)) .alignsMarkStylesWithPlotArea(false) } } } Which produces this: So here, all the different .foregroundStyle LinearGradients are being ignored AND the .alignsMarkStylesWithPlotArea(false) is also ignored - the amount of pink on the first mark is different to the second and third 🤷‍♂️ Has anyone encountered this. Are AreaMarks the correct choice or are they just not setup to create this type of data display. Thanks
3
0
751
Jun ’25
Fullscreen API web standard is unacceptably missing on iPhone
It is outrageous that Apple continue to fail to implement the Fullscreen API web standard for web apps on iPhone only, which is so important to accessibility and web app functionality. The only possible reason for this block is commercial: to promote iOS apps instead of browser based web apps. To quote a client from a major agency just now - a typical enquiry : We value accessibility greatly, and we noticed that the embedded player is missing a full screen button on iPhone. Everything else works perfectly fine, including a full screen button that appears on the mobile webpage on android devices. Is there any way we can include a button to enable full screen view for our viewers in your player that are going to watch it on iOS devices? To which, as usual, we have to reply: Apple unfortunately block fullscreen mode from being used with all web applications on iPhone. Apple will allow this to be displayed fullscreen on MacBooks and iPads, but currently not on on iPhone - so we have to hide the fullscreen button there. So fullscreen works on all devices and browsers apart from on iPhone. As you've seen with Android, all other devices and browsers follow the universal 'Fullscreen API' web standard to allow full screen. You're probably familiar with seeing the fullscreen button on normal linear videos on iPhone. These use Apple's native video player, which doesn't let buttons and scripts be used on top of it - just a single video, not an interactive web application. Our player looks like a video player but it is actually a web app combining multiple different video clips connected together by code and styling. They block it on iPhones for reasons known only to them, but the assumption is that it is to incentivise people to make iOS apps instead of web apps. The web development community is hopeful that Apple will change this unfortunate restriction soon, but we have been waiting a long time in vain. We have to send this to a lot of people. It's a very bad look for Apple. In less than a month it will be 2025. We have been waiting years for this. The web standard documentation showing universal support on other devices and browsers is here: https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API This is not acceptable. It is time for Apple to stop blocking this important accessibility web standard for commercial reasons - only on iPhone. To whoever is in charge of these decisions in the Safari/Webkit team: Please just enable Fullscreen API for web apps on iPhone as soon as possible.
3
2
1k
Dec ’24
Guideline 4.3(a) - Design - Spam - automatic rejection
I previously written here, and some advices were to appeal to rejection sending them message describing uniqueness of the app. Nothing is working. In short, i have a vpn app (of course by design shares some concept with other apps that are in the app store). But since the rejection i have completely changed the ui, added built in browser, p2p messenger so users could interact with each other without any interference. The app is completely free with no ads. I thought this is it, there's no way it would reject this time, but... i get a notification with rejection repeating the same old message. I'm extremely frustrated and don't know what to do. Tried changing the logo of the app, the name to "Incognito - Messenger, VPN", app store screenshots. I've already appealed with screenshots describing unique features that other vpn apps don't have, but the message just repeats from app review team. Submission ID: 1a49ee0b-c4e2-4a36-8372-e4d3b9a8b13f Does anybody have an advice what i can do?
3
0
2.0k
Jan ’25
Open UIViewController when QR Code is scanned
Hi developers, I have a question if it is possible to open in my application not main window but a specific ViewController, when application is installed but not running. When the application is running in background and I scan QR code, then specific ViewController is opened over SceneDelegate and method 'userActivity'. But this does not work when the application is only installed, but not running. The Appstore link is here: https://apps.apple.com/us/app/don%C3%A1tor/id6473955033
3
0
881
Feb ’25
Apple keeps preventing us for updating our app
It has been over a month since we first attempted to update our app. The issue we wanted to resolve is a bug that prevents in-app purchases from functioning properly. Fixing this bug was crucial—not only for our users but also for us as a company. However, what seemed like a simple fix has turned into an absolute nightmare. Despite our app successfully undergoing 20+ updates in the past, we now face a consistent rejection under guideline 4.3(a) - Design - Spam. Every single submission has been met with the same response. We’ve made significant changes to the app, introduced numerous features, and thoroughly reviewed every aspect, yet the rejections persist. Desperate for clarity, we scheduled a call with an Apple representative. During the call, we were told that the issue was related to our app’s screenshots. We accepted their feedback, updated the screenshots, and resubmitted the app—only to be rejected again. Since then, we’ve submitted the app three additional times, each with new sets of screenshots. Yet, the outcome has remained unchanged. Every review has been completed within about 20 minutes, with the same generic response: "Hello, The issues we previously identified still need your attention. If you have any questions, we are here to help. Reply to this message in App Store Connect and let us know." We’ve now updated the screenshots three times, but nothing has changed. Is the issue truly related to the screenshots? Or is there something else at play? We’ve already spent over 30 days trying to resolve this. Should we continue uploading a 4th, 5th, or even 6th set of screenshots, only to receive the same rejection? The lack of clarity is incredibly disheartening. I’ve pleaded with Apple to provide specific, actionable feedback so we can address the problem effectively, but the responses are always the same—copy-pasted and vague. I’m feeling completely devastated and frustrated. At this point, I’m even considering giving up on my job entirely. If anyone has advice or insights, please help. I don’t know what to do anymore.
3
0
390
Jan ’25
Guideline 4.3(a) - Design - Spam
Dear App Review team, My app Goodie AI (Apple ID 6741483227) has been flagged as violating Guideline 4.3(a) - Design - Spam. I thought I would reach out to the team to explain that Goodie AI is an entirely original concept, and would seek guidance on if we misunderstood what specifically the problem with the submission is. DESCRIPTION Please suggest next steps? We've already appealed, and have resubmitted the app. Thanks! SCREENSHOTS ATTACHED
3
0
608
Mar ’25
iPad/iPhone - Display best practices….
So…I am hitting a wall here and could use some guidance towards best practice. I’ve developed an app in Xcode/SwiftUI that renders just fine on the iPhone - text, images, buttons, frames…everything is nicely centered on the screen or scrolls where and when I want. The iPad though…not so much. I’m having issues with tops and bottoms being cut off in scrollviews. These are just straight up text screens too - the ones with other elements/controls…they’re rendering fine. I’ve tried a mix of geometry, vstack, scrollview, padding, spacers…the lot of it. Nothing I seem to do works - the views do not want to fill and fit properly. And, of course, the issue becomes worse the moment you flip the iPad into landscape view. Or use the 13” models. I’d imagine others are battling these issues as well and found solutions, so I decided to hit up the brain trust.
3
0
143
Apr ’25
Scrollview and a background image set to scaledToFill....
I've been beating my head against the wall over a scrollview issue where the top and bottom are cut off in landscape mode. Portrait mode - everything runs swimmingly. The moment I flip the iPad on its side, though, I lose about a quarter of the view on the top and bottom. I thought this was something to do with framing or such; I ran through a myriad of frame, padding, spacer, geometry...I set it static, I set it to dynamically grow, I even created algorithms to try to figure out how to set things to the individual device. Eventually, I separated the tablet and phone views as was suggested here and on the Apple dev forums. That's when I started playing around with the background image. Right now I have.... ZStack { Image("background") .resizable() .scaledToFill() .ignoresSafeArea() ScrollView { VStack(spacing: 24) {.... The problem is the "scaledToFill". In essence, whenever THAT is in the code, the vertical scrollview goes wonky in landscape mode. It, in essence, thinks that it has much more room at the top and the bottom because the background image has been extended at top and bottom to fill the wider screen of the iPad in landscape orientation. Is there any way to get around this issue? The desired behavior is pretty straightforward - the background image fills the entire background, no white bars or such, and the view scrolls against it.
3
0
135
Apr ’25
How to achieve a pure backdrop blur effect without predefined tint color in SwiftUI / UIKit?
Hi everyone, I’m currently trying to create a pure backdrop blur effect in my iOS app (SwiftUI / UIKit), similar to the backdrop-filter: blur(20px) effect in CSS. My goal is simple: • Apply a Gaussian blur (radius ~20px) to the background content • Overlay a semi-transparent black layer (opacity 0.3) • Avoid any predefined color tint from UIBlurEffect or .ultraThinMaterial, etc. However, every method I’ve tried so far (e.g., .ultraThinMaterial, UIBlurEffect(style:)) always introduces a built-in tint, which makes the result look gray or washed out. Even when layering a black color with opacity 0.3 over .ultraThinMaterial, it doesn’t give the clean, transparent-black + blur look I want. What I’m looking for: • A clean 20px blur effect (like CIGaussianBlur) • No color shift/tint added by default • A layer of black at 30% opacity on top of the blur • Ideally works live (not a static snapshot blur) Has anyone achieved something like this in UIKit or SwiftUI? Would really appreciate any insights, workarounds, or libraries that can help. Thanks in advance! Ben
3
0
152
Jun ’25