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

Drag&Drop broken in iOS18.0?
Hi, I've encountered the following phenomenon when comparing drag&drop in iOS 18.0 with iOS 17.5: Let's say you have a small child view sitting on top of a larger parent view. In iOS 18.0, when hovering over the child view with a drag object and leaving the child view, the child view will propagate a "dropInteraction:sessionDidExit:" call to the UIDropInteractionDelegate of its parent view. The parent view now thinks, that the drag object is moved away from it (which is not the case!) and in turn its delegate doesn't receive any "dropInteraction:performDrop:" calls anymore. In iOS 17.5 this case is handled correctly (without "dropInteraction:sessionDidExit:" being propagated wrongly by child views to their parent views). Is this change in behavior intended or is this a bug?
Topic: UI Frameworks SubTopic: UIKit
1
0
352
Sep ’24
Can I increase the reliability of my app intent updating my widgets?
We have widgets in our app. We're now working on a Live Activitiy with a button calling an app intent. This app intent needs to update our Widgets, and we're seeing semi-great results. When we're updating the widgets from within the app, it works great. Also from geofence triggers it usually works, so we're thinking it might have to do with the "widget update budget"? According to the docs: Cases in which WidgetKit doesn’t count reloads against your widget’s budget include when: The widget performs an app intent, such as when the user taps a button or toggles a switch. But we're not really seeing that. When I run our app from within Xcode, everything runs great all the time and the widget gets updated within milliseconds, but when running the TestFlight version is more spotty. To be clear: This is a button in a live activity, calling an app intent, and in turn, the app intent is calling reloadAllTimelines for our "regular" widgets. The live activity itself always gets updated properly. My question is basically, am I doing something wrong and can I do something to increase the consistency of the widget updating on time? Abbreviated example: final class UserEventIntent: NSObject, LiveActivityIntent { @MainActor func perform() async throws -> some IntentResult { do { let newStatus: (stat: Status, wasSame: Bool) = try await eventHelper.performEvent(status: status) WidgetCenter.shared.reloadAllTimelines() }catch { await WidgetCenterBridge.updateLiveActivityForInProgress(false) } return .result() }
2
0
427
Oct ’24
Swift pressesBegan no longer works iOS 18?
Previously this code would trigger fine on pressesBegan in iOS 17 and earlier versions, but no longer works in iOS 18. How can I start capturing pressesBegan in iOS 18? It seems like UIResponder is just not capturing the keyboard anymore? struct ContentView: View { var body: some View { KeyBoardView() } } //To Use in SwiftUI struct KeyBoardView: UIViewRepresentable{ func makeUIView(context: Context) -> KeyEventView { KeyEventView() } func updateUIView(_ uiView: KeyEventView, context: Context) { } class KeyEventView: UIView { init() { super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) { print("test") } } }
0
0
275
Oct ’24
Displaying to-many relationships in CoreData
Any CoreData experts know what could be going on here when trying to display to-many entity type relationship data? On initialisation my model does an fetch request for an entity called Expense, and some prefetching for related entities (to-many type) like this: request.relationshipKeyPathsForPrefetching = ["splits"] I was under the impression that calling a property on one of the related entities should fire the fault (if there is one) and give me the value. Here’s where it starts to go wrong. I have a property in my extension that I use in my detailed view: public var viewExpenseSplits: [ExpenseSplit] { return splits?.allObjects as? [ExpenseSplit] ?? [] } and then a list in my detail view: List(expense.viewExpenseSplits, id: \.self) { split in Text(split.amount ?? "") } Result: What's even more baffling is that I have no problem viewing these splits in the parent view. I thought perhaps I would have more luck passing the viewExpenseSplits through to the detail view instead of trying to access them from the Expense entity itself. Whilst I can print the data out when the view loads, my list still has the same problem. I thought this would be trivial. Can anyone point to me where I'm going wrong? Thanks!
1
0
369
Oct ’24
Tinted widgets have an inset background in the widget gallery only
When the home screen is in tinted mode in iOS 18, the widget gallery seems to display widgets with the background inset from the edge of the widget (i.e. negative padding). You can see this behavior in the Apple News widget too, where the full-bleed content outside of the inset is very light. This only happens in the sample gallery, not when the widgets are placed on the home screen. For my widgets, this outer edge contains important content and the clipping behavior makes the widgets look poorly designed when viewed in the gallery. Is there any way to turn this behavior off and just show the widget normally in the gallery with no weird inset — the way it will actually display when added to the home screen? If it matters, my widgets are currently configured with: .contentMarginsDisabled() .containerBackground(for: .widget) { // ... (background color) */ }
2
0
470
Oct ’24
UIHostingcontroller Reset State in UITableViewCell in iOS18
Starting from iOS18 UIHostingController behaves weirdly that it resets the state of the view when you scroll up and down of the UITableView, even though associated UITableViewCell is unique and does reuse func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if indexPath.row == 1 { let cell = tableView.dequeueReusableCell(withIdentifier: "SwiftUICell", for: indexPath) let swiftUIView = SwiftUIView() // A SwiftUI View cell.contentConfiguration = UIHostingConfiguration { // <- Here is the bug swiftUIView } return cell } else { let cell = tableView.dequeueReusableCell(withIdentifier: "NormalCell", for: indexPath) cell.textLabel?.text = items[indexPath.row] return cell } } Also in iOS18 release notes thee mentioned some fix related to this but looks like issue is not fixed Please see the attached video
Topic: UI Frameworks SubTopic: SwiftUI
1
0
339
Oct ’24
UITextField doesn't apply `keyboardType` on tvOS because of `isSecureTextEntry`
Hello everyone, Recently, I have encountered an issue in my tvOS app where a specific property of UITextField, isSecureTextEntry, set to true, was preventing another property, keyboardType, from functioning correctly. In my case, keyboardType is set to numberPad option. The problem is that during the first tap on the text field, the default keyboard with numbers, letters, and some special characters opens. However, after the second tap, the correct keyboard type with only numbers appears as I want. Removing isSecureTextEntry or setting to false solves the problem. import UIKit class ViewController: UIViewController { private let textField = UITextField() override func viewDidLoad() { super.viewDidLoad() textField.keyboardType = .numberPad textField.isSecureTextEntry = true view.addSubview(textField) setupConstraints() } }
0
0
452
Oct ’24
In PKCanvasview of IOS18, UIPanGestureRecognizer cannot be added
I am creating an application using PKCanvasview. One function of that app is the ability to trace and retrieve a UITextView that has been addSubviewed to a PKCanvasView. We have confirmed that this functionality works correctly in the simulator and on the actual device on IOS 17.4. This feature did not work correctly on the IOS18 simulator and the actual device. Is this a bug? And if it is normal behavior, is there an alternative?
0
0
439
Oct ’24
Showing .subscriptionPromotionalOffer() does not render any available offers if user already subscribed
Hi, I working with the new .subscriptionPromotionalOffer() modifier of SubscriptionStoreView, with the goal of presenting available promotional offers to users that have or have not yet subscribed to one of my subscriptions. In the former case, the promotional offers are rendered correctly along with the relevant subscription plan. But in the latter, if the user has already subscribed to the subscription, the promotional offers are not rendered at all, and the UI displays a grayed out "Current Plan" button. I expect the user to be able to enjoy this promotional offer, even it he's subscribed to the plan and he hasn't been offered the offer before. Why is it not showing for this user? Should not existing promotional offers be available to existing subscribers? struct SubscriptionsView: View { var subscriptions: [String] var offerId: String? var body: some View { SubscriptionStoreView(productIDs: subscriptions) { // UI content } .subscriptionPromotionalOffer( offer: { product, subscriptionInfo in return subscriptionInfo.promotionalOffers.first(where: { $0.id == offerId }) }, signature: { product, subscriptionInfo, promotionalOffer in return try await store.getSignature(product: product,subscriptionInfo: subscriptionInfo, promotionalOffer: promotionalOffer ) }) } }
2
0
529
Oct ’24
Updating Sequoia Beta on External Drive
For the last 2 version (18.2 beta 1 and 18.2. beta 2) I haven't been able to successfully update to either of them. I have been running Sequoia on an external drive for testing purposes and didn't have this problem with any of the 18.1 versions. I'm currently on 18.1 (public) and when I download the update for 18.2 beta 2, the update appears to run (takes about 30 mins), preparing update, the restarts. When the Mac restarts, it just boots straight back to 18.1 without having applied the update.
Topic: UI Frameworks SubTopic: General
0
0
300
Nov ’24
3rd party OSS license string in settings.bundle could not been displayed in iOS 18
Hello, Dear Developers Problem Description My team is working on functionality test in iOS18. Basically, application functionality works as expected without any modification. However, We found a small issue in settings application. iOS 17 In iOS17, 3rd party OSS license string in settings application would been displayed if the license button is been clicked. Model: iPhone SE 3 OS Version: 17.6.1 iOS 18 However, in iOS18, nothing but a blank page. Model: iPhone SE 3 OS Version: 18.0.1 Settings.bundle Below are files in settings.bundle. What I've searched Using XCode 16 makes no change Nothing about settings.bundle in iOS 18 release note A similar post: https://forums.developer.apple.com/forums/thread/764519 The solution in the post doesn't solve my problem. If you know the solution, please let me know. Best wishes.
0
0
408
Oct ’24
What Is The Recommended View Hierarchy for SwiftData Many-Many Relationships?
I am building an app where tasks can be shown on multiple selected days. The user will select a day and the available tasks should be shown. I am struggling to build a view hierarchy where the visible tasks will update when added to the currently shown day. A simplified model looks like the below: @Model final class Day { private(set) var dayID: UUID = UUID() var show: [Item]? } @Model final class Item { private(set) var itemID: UUID = UUID() @Relationship(inverse: \Day.show) var showDays: [Day]? } I have a view representing a day, and I would like it to display a list of associated tasks below. The view doesn't update if I list a day's tasks directly, e.g. List(day.show) {} I get a compile error if I build a sub view that queries Item using the day's show array: let show = day.show ?? [] let predicate = #Predicate<Item> { item in show.contains(where: { $0.itemID == item.itemID }) } I get runtime error if I flip the predicate: let dayID = day.dayID let predicate: Predicate<Item> = #Predicate<Item> { item in item.showDays.flatMap { $0.contains(where: { $0.dayID == dayID }) } ?? false } I'm at a loss of how to approach this, other that just forcing the whole view hierarchy to update every time a make a change. Is there a recommended approach to this situation please?
1
0
340
Oct ’24
Closure containing a declaration cannot be used with result builder 'ViewBuilder'
I'm new to Swift and I got this error today. I have another SwiftUI page with the same code but the error doesn't appear there. struct CardView: View { var location: String var description: String var imageName: String var body: some View { VStack{ Image(imageName) .resizable() .aspectRatio(contentMode: .fill) .frame(width: 300, height: 200) // Set a fixed height for each card .background(Color.black.opacity(0.7)) VStack(alignment: .leading) { Spacer() Text(location) .padding(15) .font(.headline) .fontWeight(.bold) .frame(width:300, alignment: .init(horizontal: .leading, vertical: .center)) .foregroundColor(.black) .bold() .background(Color.white) .clipShape(RoundedCorner(radius: 10, corners: [.topLeft, .topRight])) .padding([.leading, .trailing], -14) .padding(.bottom, 10) .offset(y: -213) .offset(x: 28) Text(description) .font(.body) .foregroundColor(.black) .frame(width:300, alignment: .init(horizontal: .leading, vertical: .center)) .background(Color.white) .clipShape(RoundedCorner(radius: 10, corners: [.bottomLeft, .bottomRight])) .padding([.leading, .trailing], 14) .padding(.bottom, 10) .multilineTextAlignment(.leading) .lineLimit(nil) .offset(y: 2) } .padding() .frame(width: 200) .fixedSize() } .frame(height: 350) // Ensure each card has a fixed height .background(Color.white) .cornerRadius(10) .shadow(radius: 5) .padding([.leading, .trailing], 5) // Add padding to the sides for spacing } } } }
Topic: UI Frameworks SubTopic: SwiftUI
1
0
263
Oct ’24
request review bug
Previously, i create an app and i'm using a userdefault with app group to enable to connect it with extension. But a bug causing me very frustating and so long to solve this, I think it just my code bug, but it was causing by the swiftui itself. Where requestReview environment, causing my navigationlink that pointing to a view that include userdefault that connect to app group is freezing while tapping. Than it just caused in my ios 16 device, and work smoothly in my ios 18 device. struct SettingView: View { @Environment(\.requestReview) var requestReview var body: some View { NavigationStack { List { Section("Configuration") { NavigationLink(destination: WidgetConfigurationView()) { Label("Widget", systemImage: "paintpalette") } } } } } struct WidgetConfigurationView: View { @Environment(\.dismiss) var dismiss @AppStorage("widgetalignment", store: UserDefaults(suiteName: "group.com.my.app")) var alignment: Int = 0 } can anyone explain why this happened? is this my mistake or the swiftui bug?
0
0
325
Oct ’24
UIViewRepresentable animations
I've tried to animate custom UIViewRepresentable with SwitfUI animations, but it doesn't work. It just sets value without interpolation. What should i do to use interpolation values in UIKit views? My example shows two "progress bars" red one is UIKit view, blue one is SwiftUI version. Sliders controls value directly, randomize button changes value to random with 5s animation. When I press button SwiftUI progress bar animates exactly as it should, but UIKit's one just jumps to final position. Set block of animatableData inside Animatable extension not called. How can I use SwiftUI animation value interpolations for UIKit? import SwiftUI import UIKit class UIAnimationView: UIView { var progress: CGFloat = 0.5 { didSet { if self.progressConstraint != nil, self.innerView != nil { self.removeConstraint(self.progressConstraint!) } let progressConstraint = NSLayoutConstraint( item: innerView!, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: min(1.0, max(0.0001, progress)), constant: 0 ) self.addConstraint(progressConstraint) self.progressConstraint = progressConstraint self.layoutIfNeeded() } } var innerView: UIView? private var progressConstraint: NSLayoutConstraint? public override init(frame: CGRect) { super.init(frame: frame) self.performInit() } public required init?(coder: NSCoder) { super.init(coder: coder) self.performInit() } private func performInit() { let innerView = UIView() innerView.translatesAutoresizingMaskIntoConstraints = false self.addSubview(innerView) self.leadingAnchor.constraint(equalTo: innerView.leadingAnchor).isActive = true self.topAnchor.constraint(equalTo: innerView.topAnchor).isActive = true self.bottomAnchor.constraint(equalTo: innerView.bottomAnchor).isActive = true let progressConstraint = NSLayoutConstraint( item: innerView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: progress, constant: 0 ) self.progressConstraint = progressConstraint self.addConstraint(progressConstraint) self.innerView = innerView self.innerView!.backgroundColor = UIColor.red self.backgroundColor = UIColor.black } } struct AnimationTest: UIViewRepresentable { var progress: CGFloat typealias UIViewType = UIAnimationView func updateUIView(_ uiView: UIAnimationView, context: Context) { print("progress: \(progress) \(context.transaction.isContinuous)") uiView.progress = progress } func makeUIView(context: Context) -> UIAnimationView { let view = UIAnimationView() view.progress = progress return view } } extension AnimationTest: Animatable { var animatableData: CGFloat { get { return progress } set { print("Animation \(newValue)") progress = newValue } } } struct AnimationDebug: View { @State var progress: CGFloat = 0.75 var body: some View { VStack { AnimationTest(progress: progress) Spacer() VStack { Slider(value: $progress, in: 0...1) { Text("Progress") } } GeometryReader { gr in Color.blue .frame( width: gr.size.width * progress, height: 48) } .frame(height: 48) Button("Randomize") { withAnimation(Animation.easeInOut(duration: 5)) { progress = CGFloat.random(in: 0...1) } } } } } struct AnimationTest_Previews: PreviewProvider { static var previews: some View { AnimationDebug() } }
2
0
1.5k
Oct ’24