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.

All subtopics

Post

Replies

Boosts

Views

Activity

quickLookPreview keyboard issues on macOS
I'm trying to add QuickLook previews to a SwiftUI app which uses Table(). I've added the .quickLookPreview() modifier to my Table(), and added a menu command for invoking it, and if I select that menu item manually, it works fine, but I have two keyboard related issues which are making it difficult to actually ship this functionality: When using the .quickLookPreview() variant for a set of URLs, keyboard navigation between the quicklook previews only works with left/right arrows, but being invoked by a Table, it would make much more sense for up/down arrows to navigate through the previews I set a .keyboardShortcut() on the menu command to use Space, since that's the normally-expected shortcut for quicklook, and it doesn't work. If I set it to some random other key (like "a") it does work, but .space doesn't do anything.
2
0
27
3h
The button click for real-time activity did not work.
We added a button in the real-time activity that responds within the app upon clicking. Now we're encountering an issue where, if you immediately click this button after swiping down to enter the notification center, it only opens the app without any scheme response. You have to wait for about 1 second after swiping down before the button can respond normally. Could you please tell us why this is happening?
0
0
12
6h
SwiftData Update Item View from Background Thread
I have a background thread that is updating a swift data model Item using a ModelActor. The background thread runs processing an Item and updates the Item's status field. I notice that if I have a view like struct ItemListView: View { @Query private var items: [Items] var body: some View { VStack { ForEach(items) { item in ItemDetailView(item) } } } } struct ItemDetailView: View { var item: Item var body: some View { // expected: item.status automatically updates when the background thread updates the `Item`'s `status`. Text(item.status) // actual: This text never changes } } Then background updates to the Item's status in SwiftData does not reflect in the ItemDetailView. However, if I inline ItemDetailView in ItemListView like this: struct ItemListView: View { @Query private var items: [Items] var body: some View { VStack { ForEach(items) { item in // Put the contents of ItemDetailView directly in ItemListView Text(item.status) // result: item.status correctly updates when the background thread updates the item. } } } } Then the item's status text updates in the UI as expected. I suspect ItemDetailView does not properly update the UI because it just takes an Item as an input. ItemDetailView would need additional understanding of SwiftData, such as a ModelContext. Is there a way I can use ItemDetailView to show the Item's status and have the UI show the status as updated in the background thread? In case details about my background thread helps solve the problem, my thread is invoked from another view's controller like @Observable class ItemCreateController { func queueProcessingTask() { Task { let itemActor = ItemActor(modelContainer: modelContainer) await itemActor.setItem(item) await itemActor.process() } } } @ModelActor actor ItemActor { var item: Item? func setItem(_ item: Item) { self.item = modelContext.model(for: item.id) as? Item } func process() async { // task that runs processing on the Item and updates the Item's status as it goes. }
0
0
68
19h
UIGraphicsImageRenderer memory issue (iOS 17.5.1)
Testing on iPhone 12 mini, I have encountered a weird situation. I am try to take snapshot of my view, which works fine but the memory is never released after the snapshot is taken. func screenshot(view: UIView, scale:Double) -> URL? { guard let containerView = view.superview, let containerSuperview = containerView.superview else { return nil } let rendererFormat = UIGraphicsImageRendererFormat() rendererFormat.scale = scale var renderer = UIGraphicsImageRenderer(bounds: containerView.frame, format: rendererFormat) let image = autoreleasepool { return renderer.image { context in containerSuperview.drawHierarchy(in: containerSuperview.layer.frame, afterScreenUpdates: true) //memory hog starts from here } } guard let data = image.heicData() else { return nil } //more code to save data to file URL and return it } initially it appears to work normally but as soon as I change the scale: rendererFormat.scale = 10 I can see a spike in memory but the problem is then the memory is never released even after the image is saved. so initially, the app uses: 35MB memory -> when processing the memory usage jumps to expected 250MB to 300MB to process large image -> after processing the memory goes down to around 90MB to 120MB but it never really returns to it's original 35MB state. Is this a bug or this is expected? If this is expected behaviour then is there any low level API to free the memory after it's job is done.
0
0
63
1d
scrollPosition(id:anchor:) freeze UI when show/hide keyboard
Hello ! This will be my first blog post. I hope I will find the solution. So, I try to use the new iOS 17+ API for ScrollView. I have an array of messages that I want to show in scroll view. And I need to scroll to bottom when I tap to Send button. When I use scrollPosition(id:anchor:), it freeze the UI. The link to the screencast to demonstrate. I think the problem might be the keyboard when it shows and hides. But I can't understand what can I do. struct ChatView: View { @ObservedObject var viewModel: CoachViewModel @State private var scrollTo: Message.ID? var body: some View { ScrollView { LazyVStack { ForEach(viewModel.messages) { message in MessageView(viewModel: viewModel, message: message) } } .scrollTargetLayout() } .scrollPosition(id: $scrollTo) .background(.primaryBackground) .onChange(of: viewModel.scrollToBottom) { if $1, let lastMessage = viewModel.messages.last { withAnimation { scrollTo = lastMessage.id } viewModel.scrollToBottom = false } } } } struct Message: Identifiable, Hashable { let id: UUID let author: MessageAuthor let text: String } final class CoachViewModel: ObservableObject { @Published var messageTextInput = "" @Published var scrollToBottom = false @Published var messages: [Message] = [...] // ... more code ... func sendMessage() { messages.append( .init( id: .init(), author: .user, text: messageTextInput ) ) messageTextInput.removeAll() scrollToBottom = true } } struct CoachView: View { @StateObject private var viewModel = CoachViewModel() @State private var isSearching = false var body: some View { VStack(spacing: 0) { Group { CoachTitleView(viewModel: viewModel, isSearching: $isSearching) ChatView(viewModel: viewModel) } .onTapGesture { UIApplication.shared.endEditing() } if isSearching { MatchboxView(viewModel: viewModel) } else { InputTextFieldView(viewModel: viewModel) } } } }
0
0
56
1d
SwiftUI SideMenu Navigation Issue
I am currently refactoring my app's side menu to be more like Twitter's. I have the UI down in terms of how the side menu looks and appears, but the issue is navigating to a view from the side menu. The views that a user can go to from the side menu are a mix of SwiftUI views & UIKit View Controllers. As of right now, when a user navigates to a view from the side menu, it presents it modally as a sheet. I want it to have regular navigation, where the user goes to the view displayed in full screen and can tap on the back button to go back to the previous view. Here is the associated code: SideMenuView.swift SideMenuViewModel.swift How can I modify the navigation logic to be like Twitter's? I've been stuck for days trying to find a fix but it has been a struggle.
0
0
91
1d
Questions Tags Saves Users Companies LABS Jobs Discussions COLLECTIVES Communities for your favorite technologies. Explore all Collectives TEAMS Ask questions, find answers and collaborate at work with Stack Overflow for Teams. Looking for your
0 I'm trying to make a list of trips that a person has gone on, and when someone has no trips in their list, it will display a ContentUnavailableView with a NavigationLink to take them to a new view. I am encountering strange issues when using the ContentUnavailableView with the NavigationLink, such as the back button being unaligned and not being able to swipe back to the previous view. I expected the ContentUnavailableView to link without any of these issues. Any guidance would be greatly appreciated.
0
0
64
1d
Location Permission Popup Not Appearing in SwiftUI App
Hello everyone, I'm working on a SwiftUI app that requires location services, and I've implemented a LocationManager class to handle location updates and permissions. However, I'm facing an issue where the location permission popup does not appear when the app is launched. Here is my current implementation: LocationManager.swift: import CoreLocation import SwiftUI class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() @Published var userLocation: CLLocation? @Published var isAuthorized = false @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined override init() { super.init() locationManager.delegate = self checkAuthorizationStatus() } func startLocationUpdates() { locationManager.startUpdatingLocation() } func stopLocationUpdates() { locationManager.stopUpdatingLocation() } func requestLocationAuthorization() { print("Requesting location authorization") DispatchQueue.main.async { self.locationManager.requestWhenInUseAuthorization() } } private func checkAuthorizationStatus() { print("Checking authorization status") authorizationStatus = locationManager.authorizationStatus print("Initial authorization status: \(authorizationStatus.rawValue)") handleAuthorizationStatus(authorizationStatus) } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { print("Authorization status changed") authorizationStatus = manager.authorizationStatus print("New authorization status: \(authorizationStatus.rawValue)") handleAuthorizationStatus(authorizationStatus) } private func handleAuthorizationStatus(_ status: CLAuthorizationStatus) { switch status { case .authorizedAlways, .authorizedWhenInUse: DispatchQueue.main.async { self.isAuthorized = true self.startLocationUpdates() } case .notDetermined: requestLocationAuthorization() case .denied, .restricted: DispatchQueue.main.async { self.isAuthorized = false self.stopLocationUpdates() print("Location access denied or restricted") } @unknown default: DispatchQueue.main.async { self.isAuthorized = false self.stopLocationUpdates() } } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { DispatchQueue.main.async { self.userLocation = locations.last } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("Location manager error: \(error.localizedDescription)") } } MapzinApp.swift: @main struct MapzinApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject private var locationManager = LocationManager() var body: some Scene { WindowGroup { Group { if locationManager.authorizationStatus == .notDetermined { Text("Determining location authorization status...") } else if locationManager.isAuthorized { CoordinatorView() .environmentObject(locationManager) } else { Text("Location access is required to use this app. Please enable it in Settings.") } } } } } Log input: Checking authorization status Initial authorization status: 0 Requesting location authorization Authorization status changed New authorization status: 0 Requesting location authorization Despite calling requestWhenInUseAuthorization() when the authorization status is .notDetermined, the permission popup never appears. Here are the specific steps I have taken: Checked the Info.plist to ensure the necessary keys for location usage are present: NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Verified that the app's target settings include location services capabilities. Tested on a real device to ensure it's not a simulator issue. I'm not sure what I might be missing. Any advice or suggestions to resolve this issue would be greatly appreciated. Thank you!
0
0
62
1d
Inline Widget Displays Custom Image Abnormally
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntax Image(uiImage: UIImage(named: String)). This successfully displays the image, but if I change the image file name in the app, the image doesn't update properly. I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly. I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
0
0
53
2d
.fullScreenCover Incorrectly Dismissed
Hi, thought I'd share some feedback (which was also sent to Apple) publicly in case anyone else is experiencing the same issue or has an idea of how to circumvent the issue while Apple investigates. TLDR: Views presented with the .fullScreenCover modifier can be incorrectly dismissed when a child view presented with a .sheet modifier inside the .fullScreenCover is dismissed. The intended behavior is that the child sheet views can be dismissed without dismissing the parent full screen cover views. It appears this bug has been present in versions of iOS 17 as well as iOS 18. Short of using something other than a .fullScreenCover to present the view, I'm still searching for a solution to this bug. Filing: FB14007758 Steps to Reproduce (see code below): Open a View in .fullScreenCover presentation In the view presented via the .fullScreenCover, add two sheet modifiers with two different views (e.g. SheetOneView, SheetTwoView) Toggle the presentation of SheetOneView and SheetTwoView randomly until the .fullScreenCover is incorrectly dismissed. Reproducible Code: import SwiftUI struct SheetOneView: View { var body: some View { Text("Sheet: 1") } } struct SheetTwoView: View { var body: some View { Text("Sheet: 2") } } struct FullScreenCoverView: View { @State var isSheetOnePresented = false @State var isSheetTwoPresented = false var body: some View { VStack(content: { Text("Full Screen Cover") HStack { Button("Open Sheet 1") { isSheetOnePresented = true } Button("Open Sheet 2") { isSheetTwoPresented = true } } .buttonStyle(.borderedProminent) .buttonBorderShape(.capsule) }) .sheet(isPresented: $isSheetOnePresented) { SheetOneView() } .sheet(isPresented: $isSheetTwoPresented) { SheetTwoView() } } } struct ContentView: View { @State var isFullScreenCoverPresented = false var body: some View { VStack { Button("Open Full Screen Cover") { isFullScreenCoverPresented = true } } .fullScreenCover(isPresented: $isFullScreenCoverPresented, content: { FullScreenCoverView() }) .padding() } }
1
0
51
2d
View with 2 labels of dynamic height
Hello, I try to do the same as the UIListContentConfiguration. Because I want to have a UITableViewCell with an image at beginning, then 2 Labels and an image at the end (accessoryView/Type should also be usable). I also want to have the dynamic behavior of the two labels, that if one or both of them exceeds a limit, that they are put under each under. But I cannot use the UIListContentConfiguration.valueCell, because of the extra image at the end. So I have tried to make a TextWrapper as an UIView, which contains only the two UILabels and the TextWrapper should take care of the dynamic height of the UILabels and put them side to side or under each other. But here in this post Im only concentrating on the issue with the labels under each other, because I have managed it to get it working, that I have two sets of Constraints and switch the activeStatus of the constraints, depending on the size of the two labels. But currently only the thing with the labels under each under makes problems. Following approaches I have tried for the TextWrapper: Using only constraints in this Wrapper (results in ambiguous constraints) Used combinations of constraints + intrinsicContentSize (failed because it seems that invalidateIntrinsicContentSize doesn't work for me) Approach with constraints only Following code snippet results in ambiguous vertical position and height. Because I have 3 constraints (those with the defaultHigh priorities). class TextWrapper: UIView { let textLabel = UILabel() let detailLabel = UILabel() init() { super.init(frame: .zero) self.addSubview(self.textLabel) self.addSubview(self.detailLabel) self.textLabel.numberOfLines = 0 self.detailLabel.numberOfLines = 0 self.directionalLayoutMargins = .init(top: 8, leading: 16, bottom: 8, trailing: 8) self.translatesAutoresizingMaskIntoConstraints = false self.textLabel.translatesAutoresizingMaskIntoConstraints = false self.detailLabel.translatesAutoresizingMaskIntoConstraints = false // Content Size self.textLabel.setContentCompressionResistancePriority(.required, for: .vertical) self.detailLabel.setContentCompressionResistancePriority(.required, for: .vertical) // Constraints self.textLabel.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor).isActive = true self.textLabel.topAnchor.constraint(equalTo: self.layoutMarginsGuide.topAnchor).constraint(with: .defaultHigh) self.textLabel.widthAnchor.constraint(lessThanOrEqualTo: self.layoutMarginsGuide.widthAnchor).isActive = true self.detailLabel.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor).isActive = true self.detailLabel.topAnchor.constraint(equalTo: self.textLabel.bottomAnchor, constant: 2).constraint(with: .defaultHigh) self.detailLabel.bottomAnchor.constraint(equalTo: self.layoutMarginsGuide.bottomAnchor).constraint(with: .defaultHigh) self.detailLabel.widthAnchor.constraint(lessThanOrEqualTo: self.layoutMarginsGuide.widthAnchor).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } Approach with intrinsicContentSize Pretty similar to the above, with only difference that I invalidate the intrinsicContentSize in the layoutSubviews, because at the first call of the intrinsicContentSize the width of the View is zero. I also tried different things like setNeedsLayout with layoutIfNeeded but nothing really works. After I invalidate the intrinsicContentSize in the layoutSubviews the intrinsicContentSize is called with the correct width of the View and calculates the correct height, but the TableView doesn't update the height accordingly. class TextWrapper: UIView { let textLabel = UILabel() let detailLabel = UILabel() init() { super.init(frame: .zero) self.addSubview(self.textLabel) self.addSubview(self.detailLabel) self.textLabel.numberOfLines = 0 self.detailLabel.numberOfLines = 0 self.directionalLayoutMargins = .init(top: 8, leading: 16, bottom: 8, trailing: 8) self.translatesAutoresizingMaskIntoConstraints = false self.textLabel.translatesAutoresizingMaskIntoConstraints = false self.detailLabel.translatesAutoresizingMaskIntoConstraints = false // Content Size self.textLabel.setContentCompressionResistancePriority(.required, for: .vertical) self.detailLabel.setContentCompressionResistancePriority(.required, for: .vertical) // Constraints self.textLabel.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor).isActive = true self.textLabel.topAnchor.constraint(equalTo: self.layoutMarginsGuide.topAnchor).constraint(with: .defaultHigh) self.textLabel.widthAnchor.constraint(lessThanOrEqualTo: self.layoutMarginsGuide.widthAnchor).isActive = true self.detailLabel.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor).isActive = true self.detailLabel.topAnchor.constraint(equalTo: self.textLabel.bottomAnchor, constant: 2).constraint(with: .defaultHigh) self.detailLabel.widthAnchor.constraint(lessThanOrEqualTo: self.layoutMarginsGuide.widthAnchor).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override var intrinsicContentSize: CGSize { let maxLabelWidth = self.bounds.width guard maxLabelWidth > 0 else { // The first time it has a width of 0, so we are giving a default height in this case, to dont produce a error in TableView return CGSize(width: UIView.noIntrinsicMetric, height: 44) } let textLabelSize = self.textLabel.sizeThatFits(CGSize(width: maxLabelWidth, height: .greatestFiniteMagnitude)) let detailLabelSize = self.detailLabel.sizeThatFits(CGSize(width: maxLabelWidth, height: .greatestFiniteMagnitude)) let totalHeight = textLabelSize.height + detailLabelSize.height + 16 return CGSize(width: UIView.noIntrinsicMetric, height: totalHeight) } override func layoutSubviews() { super.layoutSubviews() self.invalidateIntrinsicContentSize() } I also tried to use the intrinsicContentSize with only layoutSubviews, but this haven't worked also. Does anybody have ran into such issues? And know how to fix that?
2
0
53
2d
Inline Widget Displays Custom Image Abnormally
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntaxImage(uiImage: UIImage(named: String))This successfully displays the image, but if I change the image file name in the app, the image doesn't update properly. I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly. I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
0
0
35
2d
Title Bar Height Impact on Window Size in SwiftUI on macOS
In a SwiftUI macOS application, when removing the title bar by setting window.titleVisibility to .hidden and window.titlebarAppearsTransparent to true, the title bar space is still accounted for in the window height. This results in a delta (red area) in the height of the window that cannot be ignored by usual SwiftUI view modifiers like .edgesIgnoringSafeArea(.top). My actual view is the blue area. I want to have the view starting in the top safeArea and the window to be the exact size of my view. I am struggling to achieve this. I have also tried with window.styleMask.insert(.fullSizeContentView) to no effect. Can I get some help? 🙂 Here is my source code to reproduce this behavior: windowApp.swift @main struct windowApp: App { @NSApplicationDelegateAdaptor private var appDelegate: AppDelegate var body: some Scene { WindowGroup { ContentView() .edgesIgnoringSafeArea(.top) .background(.red) .border(.red) } } } class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { if let window = NSApplication.shared.windows.first { window.titleVisibility = .hidden window.titlebarAppearsTransparent = true window.styleMask.insert(.fullSizeContentView) } } } ContentView.swift import SwiftUI struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .frame(minWidth: 400, minHeight: 200) .background(.blue) } }
0
0
72
2d
iPhone and iPad Collaboration
Hello, I'm building apps for iPhone and iPad. Those are working together like a 2-screen Nintendo switch. Is there any way for communication between iPhone and iPad without an outside server? PAN(personal area network) could be a solution, but I could not find any information to use it for my case. If the iPad is connected to iPhone as a personal hotspot (though there's no cell tower), they should be communicate each other. I think there's a better way for my case. Could anyone can tell me where I start to looking for? Thanks, JJ
0
0
75
2d
Compact screens, keyboard and dynamic type UI issues
When testing my app on an iPhone SE i noticed an issue with the UI when editing some text in a text field. When the keyboard comes up it pushes everything in the view up and part of the text field gets covered by the navigation title and buttons. It gets worse when testing dynamic fonts and changing the text to XXLarge or higher. There are no issues on a larger screen. Is it possible to prevent the keyboard from push up the content of the view when it is displayed? This is with the default font of large. This is with the extra large text var body: some View { NavigationStack { VStack { HStack { Text("Name") Spacer() TextField("Name", text: $name) .multilineTextAlignment(.trailing) .textFieldStyle(.roundedBorder) .frame(width: 240) .onChange(of: name) { if name.count >= 10 { isShowingLongNameWarning = true } else { isShowingLongNameWarning = false } } } VStack(alignment: .trailing){ HStack { Text("Short Name") Spacer() TextField("Short Name", text: $shortName.max(shortNameCharacterLimit)) .multilineTextAlignment(.trailing) .textFieldStyle(.roundedBorder) .frame(width: isShowingLongNameWarning ? 215 : 240) if isShowingLongNameWarning { VStack { Image(systemName: "exclamationmark.circle") } .popoverTip(shortNameTip) } } Text("Short Name Length: \(shortName.count) characters") .font(.caption) .foregroundStyle(shortName.count >= shortNameCharacterLimit ? .red : .primary) } HStack { Text("Fluid Amount") Spacer() TextField("Fluid Amount", value: $amount, format: .number) .multilineTextAlignment(.trailing) .textFieldStyle(.roundedBorder) .keyboardType(.decimalPad) .focused($numberPadIsFocused) .frame(width: 140) .toolbar { if numberPadIsFocused { ToolbarItemGroup(placement: .keyboard) { Spacer() Button("Done") { numberPadIsFocused = false } } } } } HStack { Text("Unit of Measure") Spacer() Picker("Unit of measure", selection: $unitOfMeasure) { ForEach(FluidUnit.allCases) { Text($0.title) } } .tint(colorScheme == .dark ? .yellow : .pink) } .accessibilityElement() Toggle("Favorite Drink", isOn: $isFavorite) Text("Drink Image") ScrollView(.horizontal) { HStack{ ForEach(DataStore.drinkImages, id: \.self) { image in Button { selectDrinkImage(imageName: image) } label: { ZStack { Image(image) .resizable() .scaledToFit() .frame(height: 100) if imageName == image { SelectedDrinkImageView() } } } .padding(.trailing, 30) } } .scrollTargetLayout() } .scrollIndicators(.hidden) .scrollTargetBehavior(.viewAligned) Spacer() .navigationTitle("Add a Drink") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Save") { addDrink() } .tint(colorScheme == .dark ? .yellow : .pink) .disabled(disableSaveButton()) } ToolbarItem(placement: .topBarLeading) { Button("Cancel") { dismiss() } .tint(colorScheme == .dark ? .yellow : .pink) } } } .padding() } }
0
0
65
2d