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
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

MSStickerView in SwiftUI not animating by default
I am working on a sticker app and I am building a custom sticker app in SwiftUI. I have created a custom UIViewRepresentable to allow a MSStickerView to be displayed in SwiftUI. I have local *.gif files in my project and I am loading them into the MSStickerView successfully, however when they are loaded in my iMessage sticker extension the stickers are not animating by default. When I tap on the MSStickerView the gif begins to animate, I'm not sure what else I can do to get this working properly in my app. Some sample code below: public struct CustomStickerView: UIViewRepresentable { var sticker: CustomSticker public init(sticker: CustomSticker) { self.sticker = sticker } public func makeUIView(context: Context) -> MSStickerView { let v = MSStickerView() if sticker.fileType == .gif { v.startAnimating() } return v } public func updateUIView(_ uiView: MSStickerView, context: Context) { uiView.sticker = sticker.sticker } } // CustomSticker public var sticker: MSSticker? { guard let imagePath = Bundle.main.path(forResource: name, ofType: ".\(fileType.rawValue)") else { print("Failed to get sticker - \(name).\(fileType.rawValue)") return nil } let path = URL(fileURLWithPath: imagePath) return try? MSSticker(contentsOfFileURL: path, localizedDescription: name) }
0
0
436
Nov ’24
[SWIFT] Accessing and controlling @IBOutlet variables from other ViewControllers.
I am having trouble accessing and controlling @IBOutlet variables from other ViewControllers. More specifically, I want to control that @IBOutlet variable based on real-time changes in the variable value of another ViewController. Control is possible in the viewcontainer that contains the @IBOutlet variable, but when trying to control it from another viewcontainer, the message "Thead1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value" appears. Is there any possible way to do it? I think this will be difficult since thread1 in the error message means the main thread, so I tried to create a thread in the viewcontainer that has the @IBOutlet variable and access the variable of another viewcontainer to control the @IBOutlet variable inside the thread, but in this case, the variable value of the other viewcontainer that changes in real time is fixed to the value at the moment the thread is created, and the value that changes in real time after that cannot be retrieved. And I don't think using threads for this purpose is a good way. I sincerely ask for help from all the experts. If I can solve this, it will be easy to create the rest of the app structure. Sincerely !
Topic: UI Frameworks SubTopic: UIKit
1
1
329
Nov ’24
Map in SwiftUI just wont follows users heading when first shown
I want to use a Map to show current location and heading, but the map first show, it just wont work. And when I switch off and switch on again, it works. codes below: BackgroundMapView.swift import SwiftUI import MapKit struct BackgroundMapView: View { var scope: Namespace.ID? private var cameraPosition: MapCameraPosition = .userLocation( followsHeading: true, fallback: .automatic ) private var locations: [Location] init(_ scope: Namespace.ID? = nil, locations: [Location]) { self.scope = scope self.locations = locations } var body: some View { Map( initialPosition: cameraPosition, scope: scope ) { MapPolyline(coordinates: locations.map({ $0.coordinate.toGCJ02 })) .stroke( .red, lineWidth: 3 ) } .mapControlVisibility(.hidden) } } #Preview { MainView() } HomeVIew.swift import SwiftUI struct HomeView: View { @StateObject private var locationManager = LocationManager() @State private var isMapEnabled = UserDefaults.isHomeMapEnabled { didSet { UserDefaults.isHomeMapEnabled = isMapEnabled } } @Namespace private var mapScope var body: some View { if isMapEnabled { BackgroundMapView(mapScope, locations: locationManager.locations) .mapScope(mapScope) } } }
1
0
489
Nov ’24
How to disable Dynamic Island expansion/interaction in SwiftUI Live Activity?
I have implemented a Live Activity with Dynamic Island support for my charging app. Currently, the Dynamic Island expands when tapped, but I want to disable this interaction completely. Here's my current implementation: **dynamicIsland: { context in DynamicIsland { // Expanded Regions DynamicIslandExpandedRegion(.leading) { // Leading expanded content } DynamicIslandExpandedRegion(.trailing) { // Trailing expanded content } DynamicIslandExpandedRegion(.bottom) { // Bottom expanded content } } compactLeading: { // Compact leading view content } compactTrailing: { // Compact trailing view content } minimal: { // Minimal view content } .keylineTint(Color.clear) }**
0
0
483
Nov ’24
Parametrized Shortcuts do not show up in Shortcuts app and search with localisation.
Hi! When my device is set to English, both search and the Shortcuts up automatically show multiple shortcuts parametrised for each value of the AppEnum - which is what I expected. When my device is set to German, I get only the basic AppShortcut without the (optional) parameter. I am using an AppEnum (see below) for the parametrised phrases and localise the phrases into German with an AppShortcuts String Catalog added to my project. Everything else seems to work, I can use my AppShortcut in the Shortcuts app and invoke it via Siri in both English and German. The Shortcuts app displays the values correctly using the localized strings. Any ideas? import AppIntents class ApolloShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: GetIntent(), phrases: [ "Get data from \(.applicationName)", "Get data from \(.applicationName) for \(\.$day)", "Get data from \(.applicationName) for the \(\.$day)" ], shortTitle: "Get Data", systemImageName: "wand.and.sparkles") } } enum ForecastDays: String, AppEnum { static var typeDisplayRepresentation: TypeDisplayRepresentation = "Day" static var caseDisplayRepresentations: [Self : DisplayRepresentation] = [ .today: DisplayRepresentation(title: LocalizedStringResource("today", table: "Days")), .tomorrow: DisplayRepresentation(title: LocalizedStringResource("tomorrow", table: "Days")), .dayAfterTomorrow: DisplayRepresentation(title: LocalizedStringResource("dayAfterTomorrow", table: "Days")) ] case today case tomorrow case dayAfterTomorrow var displayName: String { String(localized: .init(rawValue), table: "Days") } }
1
0
519
Nov ’24
How to use the mouse to select List data items
I have a question about SwiftUI and would like to ask you guys The problem is described as follows I am learning to use SwiftUI. I have a file list display window. I encapsulate the files into a structure called FileInfo and use List to display the files obtained through filemanager. I want to select files by mouse selection. But I didn't find SwiftUI support for selection, so I used Zstack to select, but I found that it is difficult to respond to selection and click events at the same time. Below is my code ZStack { List(selection: $localWorkspaceViewModel.selectedFiles) { ForEach(localWorkspaceViewModel.files.indices, id: \.self) { index in ZStack { } .contextMenu{ // ... } .onTapGesture(count: 2) { // ... } .onTapGesture(count: 1) { // ... } .onDrag { // ... } } .listRowInsets(EdgeInsets()) .listRowSeparator(.hidden) } .contextMenu { // ... } .onDrop(of: ["public.data"], isTargeted: nil) { providers in // ... } Color.clear .contentShape(Rectangle()) .gesture( DragGesture(minimumDistance: 20) .onChanged { value in print() if !isDragging { dragStartPoint = value.startLocation isDragging = true } // ... } .onEnded { _ in isDragging = false } ) .allowsHitTesting(!isDragging) if isDragging { Rectangle() .fill(Color.blue.opacity(0.2)) .frame(width: selectionRect.width, height: selectionRect.height) .position(x: selectionRect.midX, y: selectionRect.midY) .overlay( Rectangle() .stroke(Color.blue, lineWidth: 1) ) .allowsHitTesting(false) } } The code problem is described as follows When the line of code .allowsHitTesting(!isDragging) sets the static value to true or false, the click and drag event of the List item behaves normally or the box selection of Color.clear behaves normally, but only one of them behaves normally. However, after setting it to !isDragging, only one of them behaves normally. I would like to ask how to solve this problem. I would be very grateful if you can give me a solution.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
280
Nov ’24
Unable to change TabView's background color
Hello, I seem to be unable to change TabView's background color (not the bar, but the background of the entire TabView), no matter what I try. What I am looking for: To make the TabView's background clear. My code: TabView(selection: $activeScreen) { Screen1() .tabItem { Label("Menu", systemImage: "list.dash") } } Screen1 is defined as: struct Screen1: View { var body: some View { VStack { Text("Hello") } .frame(maxWidth: .infinity, maxHeight: .infinity) } } What I have tried, based on suggestions online: Changing UITabBarAppearance in init(), and .onAppear() TabView().background(.clear) In all cases, the TabView's background remains either white or black, depending on the device's theme. I can change the background behind it by placing it in a ZStack, but that is not what I am looking for, I want the background itself to be clear. The only way that TabView will honor .background(.clear) is if I add the following: .tabViewStyle(.page) .indexViewStyle(.page(backgroundDisplayMode: .always)) But this changes the style of the TabView, which is not the desired behavior. Any help would be greatly appreciated, thank you!
2
1
729
Nov ’24
onChange stops working after triggering navigationDestination(isPresented:destination:) within NavigationLink
In the code below, changes to the destination value aren't captured by ViewA if: ViewB is navigated to by changing the destination property of ViewModel. ViewA is embedded in a NavigationLink or another navigationDestination. For example, the return button in ViewB doesn't work when accessed from ContentWithinNavigationLink, but it works from ContentDirect. I've also noticed that the code works if I move the presentingViewB property to the ViewModel class. However, in real code, that significantly increases the complexity of ViewModel, as I have more than ten destinations to handle. Each bound with different shapes of data. I'd prefer to store an enum value in ViewModel, listen to it in ViewA, and then convert it to boolean flags and properties in ViewA—just for iOS 16 compatibility. For iOS 17 and above, the enum works perfectly with navigationDestination(item:destination:). class ViewModel: ObservableObject { @Published var destination = "" func gotoB() { destination = "ViewB" } func reset() { destination = "" } } struct ContentWithinNavigationLink: View { var body: some View { NavigationStack { NavigationLink { ViewA() } label: { Text("Goto A") } } } } struct ContentDirect: View { var body: some View { NavigationStack { ViewA() } } } struct ViewA: View { @State private var presentingViewB = false @StateObject private var viewModel = ViewModel() var body: some View { Button { viewModel.gotoB() } label: { Text("goto ViewB") } .navigationDestination(isPresented: $presentingViewB) { ViewB().environmentObject(viewModel) } .onChange(of: viewModel.destination) { newValue in if newValue == "ViewB" { presentingViewB = true } else { presentingViewB = false } } } } struct ViewB: View { @EnvironmentObject var viewModel: ViewModel var body: some View { Button { viewModel.reset() } label: { Text("Return") } .navigationBarBackButtonHidden() } } The reason of using code like Button { viewModel.gotoB() } label: { Text("goto ViewB") } in ViewA is because in real code the Button is actually several subviews where the navigation-triggering code is deeply nested.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
295
Nov ’24
Search Bar does not work on iOS 18
I belong to an EC shop application developers' team, and we got a crame from a small part of our customers about our application. "Search Bar does not work on iOS 18." This bug doesn't appear on most of our devices updated to iOS 18.0. In some cases, it disappeared by turning [Settings > Accessibility > Touch > Reachability] off. But it is not the same for all customers found the bug. I'm looking for how to fix this bug, and why it happens. I'm not sure but I doubt that this may be a bug of iOS18, UIKit, RxCocoa, RxSwift, or something else. Any information would be welcome. import UIKit import RxSwift import RxCocoa @IBDesignable public final class SearchBar: UISearchBar { var textField: UITextField { if #available(iOS 13.0, *) { return searchTextField } else { return value(forKey: "_searchField") as! UITextField } } private let disposeBag = DisposeBag() private func bind() { textField.rx.isFirstResponder .bind(to: Binder(self) { me, isFirstResponder in // This doesn't work in some iOS 18 devices. me.textField.attributedPlaceholder = placeholderAttributedString(isFirstResponder: isFirstResponder) me.textField.backgroundColor = isFirstResponder ? Asset.Colors.whiteTwo.color : .white if me.useCancelButton { me.showsCancelButton = isFirstResponder } if me.useBookmarkButton { me.showsBookmarkButton = !isFirstResponder } }) .disposed(by: disposeBag) } public override init(frame: CGRect) { super.init(frame: frame) commonInit() } public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } public override func awakeFromNib() { super.awakeFromNib() commonInit() } public override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() commonInit() } private func commonInit() { bind() } } extension Reactive where Base: SearchBar {} import UIKit import RxSwift import RxCocoa @IBDesignable public final class SearchHeaderView: UIView { @IBOutlet private weak var searchBar: SearchBar! @IBOutlet private weak var cartContainerView: UIView! private let disposeBag = DisposeBag() public override init(frame: CGRect) { super.init(frame: frame) loadFromNib() commonInit() } public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } public override func awakeFromNib() { super.awakeFromNib() loadFromNib() commonInit() } public override func prepareForInterfaceBuilder() { super.prepareForInterfaceBuilder() loadFromNib() commonInit() } private func commonInit() { bind() } private func bind() { // ↓ This doesn't work in some iOS 18 devices. searchBar.textField.rx.isFirstResponder .bind(to: cartContainerView.rx.isHidden) .disposed(by: disposeBag) } } extension SearchAndCartHeaderView: NibOwnerLoadable {}
1
1
632
Nov ’24
Potential Issue in "Display Distinct Layouts Per Section" Documentation Example
Hi everyone, I was exploring the Display Distinct Layouts Per Section section of the Apple documentation and noticed a potential issue in the example code provided. Specifically, in the createLayout method of the TwoColumnViewController in the sample project, the item size appears to be incorrectly described. The documentation states that the item size is ignored because the items are organized in columns, but in practice, the size is considered. When running the sample project without any modifications, the layout doesn't behave as described or expected. Here’s what I observed: The items are not displayed as intended in a two-column layout. Modifying the item size explicitly affects the layout, contrary to the documentation's claim that the size is ignored. This seems to be a mismatch between the documentation and the actual implementation. Could this be clarified or corrected? Has anyone else encountered this issue? If so, are there any recommended adjustments to the sample code to achieve the intended layout? Thanks in advance for any insights or updates on this! https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views#4461906
Topic: UI Frameworks SubTopic: UIKit
0
2
260
Nov ’24
iOS 18 MapKit discrepancy between physical devices and simulators
I have noticed a discrepancy between behavior on physical devices and simulators in iOS 18. I am using the latest MapKit APIs to fetch MKMapItems using the following MKLocalSearch: private func performLocalSearch(_ query: String) async throws -> [MKMapItem] { let request = MKLocalSearch.Request() request.naturalLanguageQuery = query let search = MKLocalSearch(request: request) return try await search.start().mapItems } This returns an array of MKMapItem on both the simulator and physical device. The key difference is my physical device (iOS 18.1.1) is missing the MKMapItem's identifier value. On the simulator, identifier is always populated in addition to my search. Any ideas on how to resolve this? The new MapKit API for those curious: @available(iOS 6.0, *) open class MKMapItem : NSObject { @available(iOS 18.0, *) open var identifier: MKMapItem.Identifier? { get }
1
0
491
Nov ’24
Set filename to use for "Save to Files" with ShareLink?
Isn't there no way to set the default filename to use when we want to save a DataRepresentation to a file? If I export to JSON, the filename is "JSON.json" is used by iOS, even if I set the name to use in SharePreview. struct ContentView: View {     let car = Car(id: UUID(), name: "911", items:                     [Item(id: UUID(),date: .now, desc: "oil change"),                      Item(id: UUID(),date: .now, desc: "Battery")])     var body: some View {         VStack {             ShareLink(item: car, preview: SharePreview(car.name))         }         .padding()     } } extension UTType {     static var car: UTType = UTType(exportedAs: "com.acme.cararchive") } struct Car: Codable {     let id: UUID     let name: String     let items: [Item] } extension Car: Transferable {     static var transferRepresentation: some TransferRepresentation {         DataRepresentation(contentType: .json) { archive in             try JSONEncoder().encode(archive)         } importing: { data in             try JSONDecoder().decode(Car.self, from: data)         }     } } struct Item: Codable {     let id: UUID     let date: Date     let desc: String }
4
0
2.6k
Nov ’24
Linked list?
The code below works, in that it successfully creates an item and attached it to the parent item, but the parent view doesn't show the new child until you navigate away from the parent and then back to it. Parent: Child1 Child2 // Add Child 3 and this does not refresh when returning through the dismiss() call, but if I navigate to the grand Parent, and then back to the Parent, Child 3 is there. Any ideas? NavigationStack { Form { LabeledContent { TextField("Item", text: $name) } label: { Text("Item:") } } .navigationTitle("Add New Item") .toolbar { Button("Save") { var tmp = Item(timestamp: Date(), name: name, parent: itemParent) if(itemParent != nil) { itemParent!.children.append(tmp) } context.insert(tmp) try? context.save() dismiss() } } }
2
0
499
Nov ’24
Issue with NavigationStack, TabView and List
Hi, I'm experiencing a layout issue in SwiftUI when using TabView, NavigationStack, and a List in a specific navigation flow. Here's how to reproduce it: Tap on Tab 3. Tap "Tap Me to go to the subview" to navigate to the detail view. In the detail view, tap Back to return to Tab 3. Tap "Tap Me to go to the subview" again. Problem: When returning to the detail view, the content (especially the List) appears incorrectly positioned within the safe area, as if it's overlapping or misaligned with the navigation bar. This happens only when navigating back and forth after dismissing a sheet presented from a different tab. This animated gif shows the workflow to visualize the problem: Expected Behavior: The content should consistently respect the safe area and be positioned correctly under the navigation bar. Thanks in advance for your help! Here is the complete code to reproduce the issue: import SwiftUI @Observable class MenuSelector { var initialIndex: Int var customTabIndex: Int var isCustomTabSelected: Bool = false private var previousIndex: Int init(customTabIndex: Int, initialIndex: Int = 0) { self.initialIndex = initialIndex self.customTabIndex = customTabIndex self.itemSelected = initialIndex self.previousIndex = initialIndex } var itemSelected: Int { didSet { if itemSelected == customTabIndex { previousIndex = oldValue itemSelected = oldValue isCustomTabSelected = true } } } } struct NavigationStackSpikeView: View { @State private var tabSelector = MenuSelector(customTabIndex: 1) var body: some View { TabView(selection: $tabSelector.itemSelected) { Text("Tab 1") .tabItem { Text("Tab 1") } .tag(0) Text("I want to present a sheet for this tab") .tabItem { Text("Action") } .tag(1) Tab3View() .tabItem { Text("Tab 3") } .tag(2) } .sheet(isPresented: $tabSelector.isCustomTabSelected) { SheetView() } } } struct Tab3View: View { @State private var navigationPath = NavigationPath() var body: some View { NavigationStack(path: $navigationPath) { VStack { NavigationLink(value: Destination.subview) { Text("Tap Me to go to the subview") } } .navigationDestination(for: Destination.self) { destination in switch destination { case .subview: DetailView() } } } } enum Destination: Hashable { case subview } } struct DetailView: View { var body: some View { VStack { List { Text("A detail") } .listStyle(.plain) } .navigationTitle("Details") .navigationBarTitleDisplayMode(.inline) } } struct SheetView: View { @Environment(\.dismiss) var dismiss var body: some View { VStack { Text("I'm a sheet") Button("Dismiss") { dismiss() } } } } #Preview { NavigationStackSpikeView() }
0
0
326
Nov ’24
UIDocumentPickerViewController fullScreen not working
When I present a UIDocumentPickerViewController I want it to occupy the fullscreen but it never displays as fullscreen The modalPresentationStyle seems to have no effect no matter what I set it to Running the code with DispatchQueue.main.async did not help either Here is the code Anybody got any suggestions? `@objc private func plusButtonPressed() { DispatchQueue.main.async { let picker = UIDocumentPickerViewController(documentTypes: [kUTTypeData as String], in: .import) picker.delegate = self picker.modalPresentationStyle = .fullScreen self.present(picker, animated: true) } }`
0
0
521
Nov ’24
QLPreviewController freezes when playing Videos
In my iOS App I present a QLPreviewController where I want to display a locally stored Video from the iPhone's document directory. let previewController = QLPreviewController() previewController.dataSource = self self.present(previewController, animated: true, completion: nil) func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { let url = urlForPreview return url! as QLPreviewItem } This seems to work fine for all but one of my testflight users. He is using an iPhone 12 with iOS18.0.1. The screen becomes unresponsive. He cannot pause the video, share it or close the QLPreviewController. In his logfile I see the following error... [AVAssetTrack loadValuesAsynchronouslyForKeys:completionHandler:] invoked with unrecognized keys ( "currentVideoTrack.preferredTransform") Any ideas?.
1
0
388
Nov ’24
Disable new tab bar look
Hi, I am trying out the new UITabBar stuff in iOS18, and I don't think it'll be a good fit for my app. Is there a way to revert to the old iPad UITabBar look and placement that we've been using before? I don't want to make such a big change like this just yet, but I would need to make other changes to the app as well and I don't want to use the new UITabBar just yet. Is there a way to achieve this?
Topic: UI Frameworks SubTopic: General Tags:
32
19
21k
Nov ’24