Using the new floating tab bar with ios18 on ipad with an RTL language, when the tabbar is correctly flipped and the right buttons become left buttons, the buttons are pushed off the screen on initial load but do come back after some navigating / reloading, have recreated in a fresh project.
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
I have a scrollview displaying a sequence of circles, which a user should be able to scroll through to select an item. When the user stops scrolling and the animation comes to rest the circle selected should display screen-centered.
I had hoped to achieve this using .scrollPosition(id: selectedItem, anchor: .center) but it appears that the anchor argument is ignored when scrolled manually. (BTW - I searched but didn't locate this aspect in the Apple documentation so I'm not confident that this observation is really correct).
https://youtu.be/TpXDTuL5yPQ
The video shows the user-scrolling behaviour, and also the snap-to-anchor that I would like to achieve, but I would like this WITHOUT forcing a button press.
I could juggle the container size and size of the circles so that they naturally fit centered into the screen, but I would prefer a more elegant solution.
How can I force the scrolling to come to rest such that the circle glides to rest in the center of the screen/container?
struct ItemChooser: View {
@State var selectedItem: Int?
var body: some View {
VStack {
Text("You have picked: \(selectedItem ?? 0)")
ScrollHorizontalItemChooser(selectedItem: $selectedItem)
}
}
}
#Preview {
ItemChooser(selectedItem: 1)
}
struct ScrollHorizontalItemChooser: View {
@Binding var selectedItem: Int?
@State var scrollAlignment: UnitPoint? = .center
let ballSize: CGFloat = 150
let items = Array(1...6)
@State var scrollPosition: ScrollPosition = ScrollPosition()
var body: some View {
VStack {
squareUpButton
ScrollView(.horizontal) {
HStack(spacing: 10) {
showBalls
}
.scrollTargetLayout()
}
.scrollPosition(id: $selectedItem, anchor: scrollAlignment )
.overlay{ crosshairs } }
}
var crosshairs: some View {
Image(systemName: "scope").scaleEffect(3.0).opacity(0.3)
}
@ViewBuilder
var showBalls: some View {
let screenWidth: CGFloat = UIScreen.main.bounds.width
var emptySpace: CGFloat {screenWidth / 2 - ballSize / 2 - 10}
Spacer(minLength: emptySpace)
ForEach(items, id: \.self) { item in
poolBall( item)
.id(item)
}
Spacer(minLength: emptySpace)
}
@ViewBuilder
private func poolBall(_ item: Int) -> some View {
Text("Item \(item)")
.background {
Circle()
.foregroundColor(Color.green)
.frame(width: ballSize, height: ballSize)
}
.frame(width: ballSize, height: ballSize)
}
@ViewBuilder
var squareUpButton: some View {
var tempSelected: Int? = nil
Button("Square up with Anchor") {
tempSelected = selectedItem
selectedItem = 0
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
selectedItem = tempSelected ?? 0
}
}
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
I'm trying to combine a RotateGesture and a MagnifyGesture within a single SwiftUI view using SimultaneousGesture. My goal is to allow users to rotate and zoom an image (potentially at the same time). However, I’m running into a problem:
If only one gesture (say, the magnification) starts and finishes without triggering the other (rotation), it seems that the rotation gesture is considered "failed." After that, no further .onChanged or .onEnded callbacks fire for either gesture until the user lifts their fingers and starts over.
Here’s a simplified version of my code:
struct ImageDragView: View {
@State private var scale: CGFloat = 1.0
@State private var lastScale: CGFloat = 1.0
@State private var angle: Angle = .zero
@State private var lastAngle: Angle = .zero
var body: some View {
Image("Stickers3")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 100)
.rotationEffect(angle, anchor: .center)
.scaleEffect(scale)
.gesture(combinedGesture)
}
var combinedGesture: some Gesture {
SimultaneousGesture(
RotateGesture(minimumAngleDelta: .degrees(8)),
MagnifyGesture()
)
.onChanged { combinedValue in
if let magnification = combinedValue.second?.magnification {
let minScale = 0.2
let maxScale = 5.0
let newScale = magnification * lastScale
scale = max(min(newScale, maxScale), minScale)
}
if let rotation = combinedValue.first?.rotation {
angle = rotation + lastAngle
}
}
.onEnded { _ in
lastScale = scale
lastAngle = angle
}
}
}
If I pinch and rotate together (or just rotate), both gestures work as expected.
But if I only pinch (or, sometimes, if the rotation amount doesn’t meet minimumAngleDelta), subsequent gestures don’t trigger the .onChanged or .onEnded callbacks anymore, as if the entire gesture sequence is canceled.
I found that setting minimumAngleDelta: .degrees(0) helps because then rotation almost never fails. But I’d like to understand why this happens and whether there’s a recommended way to handle the situation where one gesture might be recognized but not the other, without losing the gesture recognition session entirely.
Is there a known workaround or best practice for combining a pinch and rotate gesture where either one might occur independently, but we still want both gestures to remain active?
Any insights would be much appreciated!
In my app, I have a ShareLink that attempts to share a movie.
struct MovieTransferable: Transferable {
let url: URL
let writeMovie: (URL) -> ()
static var transferRepresentation: some TransferRepresentation {
DataRepresentation(
exportedContentType: .movie,
exporting: {
(movie) in
// Write the movie into documents.
movie.writeMovie(movie.url)
return try! Data(contentsOf: movie.url)
})
FileRepresentation(
exportedContentType: .movie,
exporting: {
(movie) in
// Write the movie into documents.
movie.writeMovie(movie.url)
return SentTransferredFile(movie.url)
})
}
}
The ShareLink works if you try to share the movie with the Photos app, Air Drop, and iMessage. If I share to WhatsApp, the movie shows up as empty (zero length), but there's a movie. If I share to Discord, the movie is not displayed at all (only the comment). Instagram posts a dialog saying it won't allow movies and to use the app (why are they even in the ShareLink option for movies?). YouTube processes for a bit and then does nothing (no upload).
Are there things that I can do to make the Transferable accepted at more of the end points? It's at fps 30 and I've tried most of the available codec's. The size is the same as the iPhone's screen, so the aspect ratio is a bit odd. However, if I go directly to the app (Discord, etc...) upload from my phone works fine.
Any help would be appreciated to make this more viable.
I'm building an app using UITabbarController with 2 tabs: screen A and B. When standing on tab B and I taps on tab A, the order in which the events are triggered will be:
For iOS < 18:
viewWillDisappear() of screen B
tabBarController(_:didSelect:) of UITabbarController
For iOS >= 18:
tabBarController(_:didSelect:) of UITabbarController
viewWillDisappear() of screen B
So my question is this an issue or a new update from Apple on iOS 18.*?
I have a simple SwiftUI project with two basic build configurations (Debug, Release) as shown below.
I now choose Build > Scheme > Edit Scheme under Product and select Release as the current build configuration as shown below.
And the Preview canvas exhibit errors.
If I click on the Diagnostics button, it says under PREVIEW UPDATE ERROR
OptimizationLevelError: not building -Onone
”BuildSchemeCrazyDaughter.app” needs -Onone Swift optimization level to use previews (current setting is -O)
What does that mean and why don't I get the preview for the Release build configuration? Thanks.
Hello everyone,
I've run into a peculiar behavior with UINavigationController's setViewControllers on iOS 18.2 (I guess it might be reproducible on older versions) when reordering view controllers, and I wonder if anyone can shed some light on this issue.
Initial State: The navigation stack is [A - B - C].
Without Animation: Setting [A - C - B] updates the stack to: A - C - B as expected.
With Animation: Using the same command with animation changes the stack to [A - B], oddly omitting C.
Has anyone else noticed similar behavior or knows why animations might disrupt the stack's update this way? I'd appreciate any insights or suggestions.
Thanks, Dmytro
Pasting either plain or styled text into any TextEditor results in a memory leak.
import SwiftUI
struct EditorView: View {
@State private var inputText: String = ""
var body: some View {
VStack{
TextEditor(text: $inputText)
.frame(minHeight: 150)
}
}
}
Hello.
I have a scenario where a hover effect is being shown for a button that is disabled. Usually this doesn't happen but when you wrap the button in a Menu it doesn't work properly.
Here is some example code:
struct ContentView: View {
var body: some View {
NavigationStack {
Color.green
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Menu("Menu") {
Button("Disabled Button") {}
.disabled(true)
.hoverEffectDisabled() // This doesn't work.
Button("Enabled Button") {}
}
}
}
}
}
}
And here is what it looks like:
This looks like a SwiftUI bug. Any help is appreciated, thank you!
I have found a system bug with UINavigationController, UIGestureRecognizerDelegate mainly the swipe back control.
I have reproduced this in many apps, while some that use custom swipe back i can not reproduce, however any app using default uikit/swift transitions i can reproduce the flicker/previous screen flashing
The Bug: a slight tap or series of quick taps anywhere on the screen (with the slightest (1-2pt -x)confuse the system into thinking its a swipe back gesture, however instead of pushing back to previous screen the UI flickers and flashes the previous screen. for a split second, very easy to reproduce.
on screens with lots of options of boxes to tap it happens quite often.
I have removed all custom "swipe back from anywhere" logic, all custom gesture logic, and can still reproduce by tapping the edge of the screen
with only UINavigationController, UIGestureRecognizerDelegate in my navigation controller.
Please let me know the best way to get in contact with someone at apple to either build an extension to prevent this flicker or if a developer has a fix but this is rarely talked about. (velocity limits etc do not work, and just make the gesture feel awful)
all the developers i have reached out too have looked into this and have said "its an ios bug, only fix is build a custom swipe back from anywhere, or wait for apple to fix it).... as a small indie app, building my own seems daunting
Recap: quick or taps with small x movement flash previous screen instead of pushing back or simply recognizing it as a tap and not flashing previous screen. this happens with no custom code default uikit/swift. Link me your app i can probably reproduce it, I have reproduced it in X(was hard), Retro(easy), and many more.
The goal is to have a smooth native swipe/drag back from anywhere gesture while preventing flicking on fast taps or short taps with minor x movement. i have tried everything from setting limits to -x, velocity limits etc. nothing fixes this.
happy hacking!
PS i hope someone at apple calls me and i can explain this and we can fix it for every app in an update.
I think it can be dismissed with dismiss() onInAppPurchaseCompletion action handler but I have no reason to handle it, and if it's not handled it will show error alerts for you (see documentation).
How can I dismiss it and still benefit from default onInAppPurchaseCompletion action?
Thanks,
Am in the process of migrating some UIKit based apps over to SwiftUI, but for the life of me I cannot find the SwiftUI equivalent of Readable Content Margins.
I have come across some workarounds that kind of, sort of work, but do not produce the same results when compared to running the same user interface written using UIKit on several sizes of iPads in portrait and landscape orientiations.
is it something Apple has not gotten around to yet, because I realize SwiftUI is a work-in-progress, or do we not care about creating consistent readable margins in our apps anymore?
So I am looking to use a custom NSWindow application (so I can implement some enhanced resizing/dragging behavior which is only possible overriding NSWindow).
The problem is my whole application is currently SwiftUI-based (see the project here: https://github.com/msdrigg/Roam/blob/50a2a641aa5f2fccb4382e14dbb410c1679d8b0c/Roam/RoamApp.swift).
I know there is a way to make this work by dropping my @main SwiftUI app and replacing it with a SwiftUI root view hosted in a standard AppKit root app, but that feels like I'm going backwards.
Is there another way to get access (and override) the root NSWindow for a SwiftUI app?
I have a controller that displays a pdf using UIDocumentInteractionController as the presented view.
When users open it up, it shows fine.
User gets the app backgrounded and session timed out.
After timed out, when the app is brought to foreground, I bring our loginVC by removing the old VC used to show the UIDocumentInteractionController.
All the crashes are happening at this point.
I am not able to reproduce it, but our alert systems show we have crashes happening.
The code that shows the pdf is straight forward
documentViewController = UIDocumentInteractionController()
documentViewController?.delegate = self
documentViewController?.url = url
documentViewController?.presentPreview(animated: true)
and we reset it to nil in delegate documentInteractionControllerDidEndPreview
Based on the crash trace, it seems like the crash happens when our login VC replaces it and only when pdf was displayed. The reason of stressing ONLY because when we have other viewcontroller present and they are removed in a similar way, we do not see any issue.
So we always replace first and then add a new one
childViewController.willMove(toParent: nil)
childViewController.viewIfLoaded?.removeFromSuperview()
childViewController.removeFromParent()
addChild(childViewController)
view.addSubview(childViewController.view)
childViewController.view.frame = view.bounds
childViewController.didMove(toParent: self)
Raised a ticket with Apple, but I haven't heard back, and it's been a month. Posting here in case anyone experiences the same and has any solutions. I saw some related posts, and solution was to remove the pdf the moment the app goes to the background, but I am trying to find some alternate solution if possible.
Topic:
UI Frameworks
SubTopic:
UIKit
I've encountered an issue where storing a throws(PermissionError) closure as a property inside a SwiftUI View causes a runtime crash on iOS 17, while it works correctly on iOS 18.
Here’s an example of the affected code:
enum PermissionError: Error {
case denied
}
struct PermissionCheckedView<AllowedContent: View, DeniedContent: View>: View {
var protectedView: () throws(PermissionError) -> AllowedContent
var deniedView: (PermissionError) -> DeniedContent
init(
@ViewBuilder protectedView: @escaping () throws(PermissionError) -> AllowedContent,
@ViewBuilder deniedView: @escaping (PermissionError) -> DeniedContent
) {
self.protectedView = protectedView
self.deniedView = deniedView
}
public var body: some View {
switch Result(catching: protectedView) {
case .success(let content): content
case .failure(let error): deniedView(error)
}
}
}
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
PermissionCheckedView {
} deniedView: { _ in
}
}
}
}
Specifically this is the stack trace (sorry for the picture I didn't know how to get the txt):
If I use var protectedView: () throws -> AllowedContent without typed throws it works.
A document-based app that's been running fine on iPad and Mac Catalyst has stopped working on the Mac as of Sequoia 15.3. After the user selects a document to open, my app never gets called back from Apple's framework. (The app works fine on iPadOS.) Anybody else see this?
I filed a feedback, FB16506048, several weeks ago but have had no reply.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I config of an alternate icon on the App Store Connect product page optimization. After the app launches, can I retrieve the name of this configured icon through UIApplication.shared.alternateIconName?
Hello, I can't seem to set any breakpoint in didSet for all properties inside Observable.
Is this a bug?
XcodeVersion 15.2
(15C500b)
Thanks!
My app is experiencing a recurring crash in the PRD environment, but it cannot be reproduced locally or in QA testing.
Below is the crash log—I’d appreciate any help or insights on how to diagnose and resolve this issue. Thank you!
0 libobjc.A.dylib 0x2354 objc_release_x0 + 16
1 libobjc.A.dylib 0x2354 objc_release + 16
2 libobjc.A.dylib 0x4e38 AutoreleasePoolPage::releaseUntil(objc_object**) + 204
3 libobjc.A.dylib 0x4b8c objc_autoreleasePoolPop + 260
4 FrontBoardServices 0x1f4d0 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 176
5 FrontBoardServices 0x2eb90 -[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:] + 468
6 libdispatch.dylib 0x3fa8 _dispatch_client_callout + 20
7 libdispatch.dylib 0x79f0 _dispatch_block_invoke_direct + 284
8 FrontBoardServices 0x18378 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 52
9 FrontBoardServices 0x182f8 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 240
10 FrontBoardServices 0x181d0 -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 28
11 CoreFoundation 0x73f3c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
12 CoreFoundation 0x73ed0 __CFRunLoopDoSource0 + 176
13 CoreFoundation 0x76b94 __CFRunLoopDoSources0 + 344
14 CoreFoundation 0x75d2c __CFRunLoopRun + 840
15 CoreFoundation 0xc8274 CFRunLoopRunSpecific + 588
16 GraphicsServices 0x14c0 GSEventRunModal + 164
17 UIKitCore 0x3ee77c -[UIApplication _run] + 816
18 UIKitCore 0x14e64 UIApplicationMain + 340
Topic:
UI Frameworks
SubTopic:
UIKit
I'm implementing a custom text editor in SwiftUI using a UITextView wrapped in a UIViewRepresentable. The text editor works for basic text entry, but I'm encountering an issue with scrolling behavior.
When the UITextView becomes the first responder (when tapped), the parent ScrollView doesn't automatically scroll to make the text view visible. Instead, the scroll position jumps to the last known position (scrolls to a different text view that was previously focused).
Here's my implementation reduced to the minimum:
struct SpacedTextEditor: View {
@Binding var text: String
var body: some View {
MinimalEditor(text: $text)
}
}
private struct MinimalEditor: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.backgroundColor = .clear
textView.delegate = context.coordinator
textView.isScrollEnabled = false
textView.text = text
return textView
}
func updateUIView(_ textView: UITextView, context _: Context) {
if textView.text != text {
textView.text = text
}
}
func makeCoordinator() -> Coordinator {
Coordinator(text: $text)
}
class Coordinator: NSObject, UITextViewDelegate {
var text: Binding<String>
init(text: Binding<String>) {
self.text = text
}
func textViewDidChange(_ textView: UITextView) {
text.wrappedValue = textView.text
}
}
}
The text editor is placed inside a ScrollView in my parent view. How can I ensure that when a user taps on the text editor, the ScrollView properly scrolls to make it fully visible or at least it doesn't jump to where the textfield is not even visible?
I need to use a custom textfield because I need to be able to modify the space between lines, and I didn't find a way to do this using the swiftUI component.
Topic:
UI Frameworks
SubTopic:
SwiftUI