I made an account on this site for the sole reason to post this.
I can not stand the IOS 18 photo app, to put it bluntly its sucks, it's made the app unusable.
I was nice, I'd thought I'd give it a month or two but no, it still sucks.
I wish I could uninstall IOS 18 solely cause of it.
I hate the UI, its utterly unintuitive.
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
Hi guys,
I've been this app for quite a while and I wanted to add audio to it but I've encountered a strange bug. Whenever I try to play the audio from the testing device, it prints out that the audio file cannot be found. I've checked multiple times the names and the code and I get no errors there whatsoever. I have no idea what might be causing this. Here's a part of the code:
`import SwiftUI
import AVFoundation
struct Card: Identifiable {
let id = UUID()
let heading: String
let description: String
let imageName: String
let detailDescription: String
let sonification: String
}
struct ExplorepageUI: View {
@State private var selectedCard: Card?
@State private var showMore = false
@State private var currentIndex = 0
@State private var currentCards: [Card] = []
let galaxies = [
Card(heading: "The Mice Galaxies",
description: "They’re located about 300 million light-years away in the constellation Coma Berenices.",
imageName: "TheMiceGalaxiesHubble",
detailDescription:"""
Their name refers to the long tails produced by tidal action, the relative difference between gravitational pulls on the near and far parts of each galaxy, known here as a galactic tide. It is a possibility that both galaxies, which are members of the Coma Cluster, have experienced collision, and will continue colliding until they coalesce. The colors of the galaxies are peculiar. In NGC 4676A a core with some dark markings is surrounded by a bluish white remnant of spiral arms. The tail is unusual, starting out blue and terminating in a more yellowish color, despite the fact that the beginning of each arm in virtually every spiral galaxy starts yellow and terminates in a bluish color. NGC 4676B has a yellowish core and two arcs; arm remnants underneath are bluish as well.
The galaxies were photographed in 2002 by the Hubble Space Telescope. In the background of the Mice Galaxies, there are over 3000 galaxies, at distances up to 13 billion light-years.
""",
sonification: "SonificationoftheMiceGalaxies"),
`class MusicPlayer: ObservableObject {
private var audioPlayer: AVPlayer?
func playSound(named sonificationFileName: String){
if let url = Bundle.main.url(forResource: sonificationFileName, withExtension: "mp3"){
print("✅ Found audio file at: \(url)")
audioPlayer = try? AVPlayer(url: url)
audioPlayer?.play()
print("🎵 Audio should now be playing!")
} else {
print("❌ Audio file not found: \(sonificationFileName).mp3")
}
}
func pause(){
audioPlayer?.pause()
}
}
I'm currently migrating a midsize (20k LOC) project to Swift structured concurrency. With complete checking turned on, it currently builds with only two warnings, both of which are related to the QLPreviewControllerDelegate protocol:
"Main actor-isolated instance method 'previewControllerDidDismiss' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode" as well as the same warning but substituting 'previewController(_:transitionViewFor:)' for the method name.
I'm confused as to how to make these nonisolated, as they use UIKit classes/subclasses as arguments and/or return types.
Exploring Live Activity feature for Apple Watch right now and found that it has this default view with "Open on iPhone" button when you tap Live Activity. That button perfectly brings iOS app to foreground as if you tapped iOS's Live Activity.
Is there a way to mimic that behavior from inside Watch app code? From inside WKApplicationDelegate, for example
Tried openSystemURL but it seems lile it's only available for tel or sms links
The dividing lines of List Section overlap, which is uncomfortable to look at.
Look at the line under "Incomplete"
I have a very simple SwiftUI app, works fine on iOS, crashes on macOS:
struct ContentView: View
{
@State var testStr: String = ""
@State var selection: TextSelection? = nil
var body: some View
{
VStack
{
TextField("Test", text: $testStr, selection: $selection)
.onChange(of: selection) {print("selection changed")}
}
.padding()
}
}
• Start app, write something in the TextField and move the cursor around.
iOS: "selection changed"
Mac: nothing (Bug ?)
• double click on some word
both Mac and iOS: "selection changed"
• write some more in the TextField
iOS: selection changed
Mac: crash
Any idea what I am doing wrong?
Gerriet.
Topic:
UI Frameworks
SubTopic:
SwiftUI
Hi,
I programmed an app to draw cards from a deck. After a card is drawn it is hidden from the deck. The drawn state is a property of a card struct in an array inside a deck struct.
This worked well in the past since iOS 14. Since Xcode 16 this does not work as before anymore.
This is the Card struct with a Boolfor the drawn state:
struct Card: Codable, Identifiable, Equatable, Hashable {
var isDrawn: Bool
…
}
The cards are stored in an array that is inside a CardDeck struct among other properties:
struct CardDeck: Codable {
var cards: [Card] = []
var cardSpacing: CGFloat
…
mutating func hideCard(card: Card) {
if let cardIndex = self.cards.firstIndex(of: card) {
self.cards[cardIndex].isDrawn = true
}
}
}
The deck is a published property of an observable DeckStore class for permanent storage:
class CardDeckStore: ObservableObject {
@Published var deck: CardDeck = CardDeck()
…
}
The DeckStore class is @StateObject in the App struct:
@main
struct CardApp: App {
@StateObject var store = OpaliaCardDeckStore()
var body: some Scene {
WindowGroup {
ContentView(deck: $store.deck)
}
}
}
Here is the simplified DrawCardsView where I present and draw the cards:
struct DrawCardsView: View {
@Binding var deck: CardDeck
var body: some View {
// Was a NavigationView before
NavigationStack() {
HStack(spacing: deck.cardSpacing) {
ForEach($deck.cards) { $card in
if card.isDrawn {
CardBackView(card: card)
.hidden()
}
else {
NavigationLink(destination: DrawnCardView(card: card, deck: $deck)) {
CardBackView(card: card)
}
}
}
}
}
}
}
To hide a drawn card, hideCard() is called in the DrawnCardView:
struct DrawnCardView: View {
var card: Card
@Binding var deck: CardDeck
@State var drawnCard: DrawnCard = .init()
var body: some View {
DrawnCardSimpleView(drawnCard: self.drawnCard)
.onDisappear(perform: {
deck.hideCard(card: self.card)
})
}
}
I am not a pro in programming and there are better solutions to program this, but this worked until I upgraded to Xcode 16. Now it seems the isDrawn state of a card does not update the DrawCardsView right away anymore. A drawn card is not hidden and still present when returning to DrawCardsView from DrawnCardView. After tapping the same card again or another update of the UI, the card will then be hidden.
I do not know the reason. It seems the binding of the isDrawn state inside an element of the card array in the observable object is not working anymore. Other properties of the observable object like cardSpacing do work as expected.
I can empty the cards array and fill it with new cards without problems in the DrawCardsView.
I eliminated the ForEach loop by addressing the array elements directly, but to no avail. I tried different solutions I found on the internet, but nothing worked.
I was under the impression that every change in an observable object would update the UI.
Any ideas for a explanation/solution?
Thanks,
Christian
Topic:
UI Frameworks
SubTopic:
SwiftUI
I have an iOS App which looks great on iPhone, portrait only, which makes a lot of use of UITableViews.
On iPad those tables look stretched out in Landscape.
On MacOS with Apple Silicon the app can be resized to any size and the table views look very stretched. There are views in the App which users want to resize so limiting app size not an option.
I've been modifying the app's table views to limit their width and centre them using constraints.
This isn't easy, it's a lot of work as UITableViewController doesn't allow for constraining the table width. Or does it?
So I've changed them to UIViewControllers with UITableView imbedded in the root UIView with constraints. Looks really nice.
Now I've just run into the limitation that static tables, which I have a number of, aren't allowed to be embedded. So how can I limit the width of them?
I really don't want to add a lot of dynamic code.
Please tell me there's an simpler, more elegant method to what really makes a much more aesthetically pleasing UI on iOS App running on iPad and MacOS?
TIA!
Hi I think I found an issue with SwiftUI List on iOS 18.0 and 18.1
Using the ContentView from the code block below: if you try to drag and drop the globe image onto the blue rows, things work fine on both iOS 17 and 18 with either List or VStack.
However if you first drag and drop the image onto the Files app and then drag the newly created PNG file back into our app, it won't work on iOS 18 with the blue row inside the List. Also there's no visual feedback when hovering that blue row (unlike the one inside the VStack).
I've tried various view modifiers but no luck so far. Any help is appreciated.
Thank you.
FB15618535
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.resizable()
.scaledToFit()
.frame(height: 100)
.draggable(Image(systemName: "globe"))
List {
Color.gray
.frame(height: 100)
Color.blue
.frame(height: 100)
.dropDestination(for: Image.self) { _, _ in
print("List dropped")
return true
}
}
VStack {
Color.gray
Color.blue
.dropDestination(for: Image.self) { _, _ in
print("VStack dropped")
return true
}
}
}
.padding()
}
}
I am using the window.level set to .floating as described here:
https://developer.apple.com/documentation/appkit/nswindow/level
The setting itself works okay. However, in a multi monitor setup, the floating window is appearing on both the screens.
How can I prevent this? My users report that before macOS Sonoma, this used to not happen. Has this behaviour changed? How can I revert back to the old behaviour?
We are using an imbedded WKWebView in a SwiftUI view. There are links within the pages being viewed - they are company pages - and some link to other pages as well as open named (or unnamed) browser tabs.
In our implementation, when there is a named (or unnamed) link to another browser tab, the view does not do anything.
Any ideas on how to allow tabs to open in some manner and allow the users to access the links?
Hello,
I am using SwiftUI ShareLink to share an image with Instagram app, but when I select "Story" option in share interface, an error happens, "Error: Something went wrong".
Has anyone had this problem? Is there a solution?
Thanks
Thanks
Topic:
UI Frameworks
SubTopic:
SwiftUI
Let's say I have a model like this:
@Model
final class DataModel {
var firstProperty: String = ""
}
Later on I create a new property as such:
@Model
final class DataModel {
enum DataEnum {
case dataCase
}
var firstProperty: String = ""
var secondProperty: DataEnum? = .dataCase
}
My expectation is for the data that is already stored, the secondProperty would be added with a default value of .dataCase. However, it's being set to nil instead. I could have sworn it would set to the default value given to it. Has that changed, or has it always been this way? Does this require a migration plan?
Developing on Monterey 12.7.5
I'm having trouble with updating subitems on NSToolbarItemGroup when selecting the item directly from the NSToolbar items array.
I select the group item off the items array on the toolbar, and then call setSubitems: on the item, with a new array of NSToolbarItems. The group item disappears from the toolbar. It seems to leave a blank invisible item in the toolbar taking up space. I can't manually reinsert the item into the toolbar until I drag out the blank item, then drag back in the real item. Once dragged back in from the palette it displays correctly.
The workaround I've come up with is to remove the item with NSToolbar removeItemAtIndex: and reinsert it with NSToollbar insertItemWithItemIdentifier:atIndex:. This works to update the subitems.
Every other toolbar item property that I've tried has been able to update the item directly in the toolbar. It's only the group item's subitems that don't want to update correctly.
Is there a correct way to do this that I'm missing? Calling [toolbar validateVisibleItems] didn't seem to help.
I want to support Genmoji input in my SwiftUI TextField or TextEditor, but looking around, it seems there's no SwiftUI only way to do it?
If none, it's kind of disappointing that they're saying SwiftUI is the path forward, but not updating it with support for new technologies.
Going back, does this mean we can only support Genmoji through UITextField and UIViewRepresentable? or there more direct options?
Btw, I'm also using SwiftData for storage.
Hi,
I'm new here. I have an app that I want to refresh a few variables at midnight. What ways can i go about doing this?
I have an AppDelegate started, but I'm not sure how to make it work, yet.
Is there an easy way to make it update?
Hey guys,
I'm totally new to Swift programming and I'm setting up a view for registering users. I use a VStack to organize the TextFields as well as a DatePicker, but the last one seems to be very rebellious.
Here's my code:
VStack {
TextField("E-Mailadresse", text: $mail)
.frame(height: 30)
.textFieldStyle(.roundedBorder)
.multilineTextAlignment(.center)
.focused($hasFocus, equals: .mail)
.onKeyPress(.tab, action: {hasFocus = .password; return .handled})
SecureField("Passwort", text: $password)
.frame(height: 30)
.textFieldStyle(.roundedBorder)
.multilineTextAlignment(.center)
.focused($hasFocus, equals: .password)
.onKeyPress(.tab, action: {hasFocus = .name; return .handled})
TextField("Name", text: $name)
.frame(height: 30)
.textFieldStyle(.roundedBorder)
.multilineTextAlignment(.center)
.focused($hasFocus, equals: .name)
.onKeyPress(.tab, action: {hasFocus = .prename; return .handled})
TextField("Vorname", text: $prename)
.frame(height: 30)
.textFieldStyle(.roundedBorder)
.multilineTextAlignment(.center)
.focused($hasFocus, equals: .prename)
.onKeyPress(.tab, action: {hasFocus = .birthday; return .handled})
DatePicker("Geb.:", selection: $birthday, displayedComponents: [.date])
.datePickerStyle(.wheel)
.clipped()
//.focused($hasFocus, equals: .birthday)
Button("Registrieren") {self.register()}
.padding(.top, 20)
.keyboardShortcut(.defaultAction)
}
.frame(width: 375)
}
And this is how it looks like:
As you can see, neither is the DatePicker centered correctly (it's more left located) nor is it clipped (reduced). I also tried adding a .frame() to itself, then I was ably to reduce it to the preferred height, but I can' reduce its width and as a result of this, I can also not write a full label like "Date of Birth" or something, because the wheel of the DatePicker always overlays it...
Is that a kind of misbehavior or am I missing something?
Thank you very much in anticipation for your feedback!
Kind regards
Kevin
The UITextView.allowedWritingToolsResultOptions has no effect to how "Writing Tools" feature works. When it is set to empty, it still offer all options in the Writing Tools popup dialog. The result is that it is not possible to limit output results to eg. only plain text, or disable tables in output.
let textView = UITextView()
textView.isEditable = true
textView.writingToolsBehavior = .complete
textView.allowedWritingToolsResultOptions = []
resulting Writing Tools has all options available. I Tested with TextKit1 and TextKit 2 setup.
tested on iPadOS 18.1 beta (22B5069a)
Report: FB15429824
Following instructions from ChatGPT, I'm trying to rearrange the order of rows in a UITableView.
- (void)tableView:(UITableView *)tableView performDropWithCoordinator:(id<UITableViewDropCoordinator>)coordinator {
NSIndexPath *destinationIndexPath = coordinator.destinationIndexPath ?: [NSIndexPath indexPathForRow:self.items.count inSection:0];
[tableView performBatchUpdates:^{
for (UITableViewDropItem *dropItem in coordinator.items) {
NSString *movedItem = dropItem.dragItem.localObject;
if (movedItem) {
NSIndexPath *sourceIndexPath = dropItem.sourceIndexPath;
if (sourceIndexPath) {
[self.items removeObjectAtIndex:sourceIndexPath.row];
[self.items insertObject:movedItem atIndex:destinationIndexPath.row];
[tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath];
}
}
}
} completion:nil];
}
Xcode is complaining that UITableViewDropItem does not exist.
The class is in all the documentation, it is just not showing up when needed!
Suggestions?
Topic:
UI Frameworks
SubTopic:
UIKit
Problem
I am developing a WebDriver agent for automation and using dictionaryRepresentation to retrieve the coordinates of the iOS app hierarchy. However, I am encountering an issue with the accuracy of the x and y coordinates.
Approach Tried
I tested the setup on:
iPhone 12 Pro Max (iOS 16.2): Accuracy issues with the coordinates were observed.
iPhone SE (3rd Generation) (iOS 16.2): Coordinates were accurate for tap actions, with no issues identified.
Observation
It appears that devices with fingerprint biometric authentication provide accurate coordinates.
Can anyone help here to understand is there anything wrong in the code. Are do we have to adjust frame of the element for different devices?
Sample Code
- (NSDictionary *)json_tree
{
NSDictionary<XCUIElementAttributeName, id>
*dictionaryRepresentation = [[self snapshotWithError:nil] dictionaryRepresentation];
return [self.class dictionaryForElementAttributes:dictionaryRepresentation recursive:YES];
}
// This method converts the dictionary to CGRect, handling any broken frame values (e.g., Infinity)
+ (CGRect)handleBrokenFrameFromDict:(id)frameDict {
if ([frameDict isKindOfClass:[NSDictionary class]]) {
CGFloat originX = [frameDict[@"X"] floatValue];
CGFloat originY = [frameDict[@"Y"] floatValue];
CGFloat sizeWidth = [frameDict[@"Width"] floatValue];
CGFloat sizeHeight = [frameDict[@"Height"] floatValue];
CGRect frame = CGRectMake(originX, originY, sizeWidth, sizeHeight);
// Replace Infinity values with CGRectZero
return (isinf(frame.size.width) || isinf(frame.size.height)
|| isinf(frame.origin.x) || isinf(frame.origin.y))
? CGRectZero // or another predefined constant like BROKEN_RECT
: CGRectIntegral(frame);
}
return CGRectZero; // If frameDict is not a valid dictionary, return CGRectZero
}
// This method converts CGRect into a dictionary representation for "rect"
+ (NSDictionary *)rectDictionaryFromCGRect:(CGRect)rect {
return @{
@"x": @(rect.origin.x),
@"y": @(rect.origin.y),
@"width": @(rect.size.width),
@"height": @(rect.size.height)
};
}
+ (NSString *)label:(NSDictionary<XCUIElementAttributeName, id> *)dict
{
XCUIElementType elementType = [dict[XCUIElementAttributeNameElementType] intValue];
NSString *label = dict[XCUIElementAttributeNameLabel];
if (elementType == XCUIElementTypeTextField || elementType == XCUIElementTypeSecureTextField) {
return label;
}
return FBTransferEmptyStringToNil(label);
}
+ (NSString *)name:(NSDictionary<XCUIElementAttributeName, id> *)dict
{
NSString *identifier = dict[XCUIElementAttributeNameIdentifier];
if (nil != identifier && identifier.length != 0) {
return identifier;
}
NSString *label = dict[XCUIElementAttributeNameLabel];
return FBTransferEmptyStringToNil(label);
}
+ (NSString *)value:(NSDictionary<XCUIElementAttributeName, id> *)dict
{
id value = dict[XCUIElementAttributeNameValue];
XCUIElementType elementType = [dict[XCUIElementAttributeNameElementType] intValue];
if (elementType == XCUIElementTypeStaticText) {
NSString *label = [self label:dict];
value = FBFirstNonEmptyValue(value, label);
} else if (elementType == XCUIElementTypeButton) {
NSNumber *isSelected = [dict[XCUIElementAttributeNameSelected] boolValue] ? @YES : nil;
value = FBFirstNonEmptyValue(value, isSelected);
} else if (elementType == XCUIElementTypeSwitch) {
value = @([value boolValue]);
} else if (elementType == XCUIElementTypeTextView ||
elementType == XCUIElementTypeTextField ||
elementType == XCUIElementTypeSecureTextField) {
NSString *placeholderValue = dict[XCUIElementAttributeNamePlaceholderValue];
value = FBFirstNonEmptyValue(value, placeholderValue);
}
value = FBTransferEmptyStringToNil(value);
if (value) {
value = [NSString stringWithFormat:@"%@", value];
}
return value;
}
+ (NSDictionary *)dictionaryForElementAttributes:(NSDictionary<XCUIElementAttributeName, id> *)dict recursive:(BOOL)recursive
{
NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
info[@"type"] = [FBElementTypeTransformer shortStringWithElementType:[dict[XCUIElementAttributeNameElementType] intValue]];
info[@"rawIdentifier"] = FBValueOrNull([dict[XCUIElementAttributeNameIdentifier] isEqual:@""] ? nil : dict[XCUIElementAttributeNameIdentifier]);
info[@"name"] = FBValueOrNull([self name:dict]);
info[@"value"] = FBValueOrNull([self value:dict]);
info[@"label"] = FBValueOrNull([self label:dict]);
// Handle the frame value
CGRect frame = [self handleBrokenFrameFromDict:dict[XCUIElementAttributeNameFrame]];
info[@"frame"] = NSStringFromCGRect(frame);
// Add the rect value
info[@"rect"] = [self rectDictionaryFromCGRect:frame];
info[@"isEnabled"] = [@([dict[XCUIElementAttributeNameEnabled] boolValue]) stringValue];
// visible
// accessible
info[@"isFocused"] = [@([dict[XCUIElementAttributeNameHasFocus] boolValue]) stringValue];
if (!recursive) {
return info.copy;
}
NSArray<NSDictionary<XCUIElementAttributeName, id> *> *childElements = [dict[XCUIElementAttributeNameChildren] isKindOfClass:[NSArray class]] ? dict[XCUIElementAttributeNameChildren] : @[];
if ([childElements count]) {
info[@"children"] = [[NSMutableArray alloc] init];
for (NSDictionary<XCUIElementAttributeName, id> * childSnapshot in childElements) {
[info[@"children"] addObject:[self dictionaryForElementAttributes:childSnapshot recursive:YES]];
}
}
return info;
}
Topic:
UI Frameworks
SubTopic:
General