I'm encountering an issue displaying a large HTML string (over 11470 characters) in a UILabel. Specifically, the Arabic text within the string is rendering left-to-right instead of the correct right-to-left direction. I've provided a truncated version of the HTML string and the relevant code snippet below. I've tried setting the UILabel's text alignment to right, but this didn't resolve the issue. Could you please advise on how to resolve this bidirectional text rendering problem?
The results of the correct and incorrect approaches are shown in the image below.
Here's the relevant Swift code:
let labelView: UILabel = {
let label = UILabel()
label.textAlignment = .right
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.semanticContentAttribute = .forceRightToLeft
label.backgroundColor = .white
label.lineBreakMode = .byWordWrapping
return label
}()
//Important!!
//It must exceed 11470 characters.
let htmlString = """
<p style=\"text-align: center;\"><strong>İSTİÂZE</strong></p> <p>Nahl sûresindeki:</p>
<p dir="rtl" lang="ar"> فَاِذَا قَرَاْتَ الْقُرْاٰنَ فَاسْتَعِذْ بِاللّٰهِ مِنَ الشَّيْطَانِ الرَّج۪يمِ </p>
<p><strong>“</strong><strong>Kur’an okuyacağın zaman kovulmuş şeytandan hemen Allah’a sığın!</strong><strong>”</strong> (Nahl 16/98) emri gereğince Kur’ân-ı Kerîm okumaya başlarken:</p> <p dir="rtl" lang="ar">اَعُوذُ بِاللّٰهِ مِنَ الشَّيْطَانِ الرَّج۪يمِ</p> <p><em>“Kovulmuş şeytandan Allah’a sığınırım” </em>deriz. Bu sözü söylemeye “istiâze<em>” denilir. “Eûzü”</em>, sığınırım, emân dilerim, yardım taleb ederim, gibi anlamlara gelir. It must exceed 11470 characters.</p>
“””
if let data = htmlString.data(using: .utf8) {
let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
]
do {
let attributedString = try NSAttributedString(data: data, options: options, documentAttributes: nil)
labelView.attributedText = attributedString
} catch {
print("HTML string işlenirken hata oluştu: \(error)")
}
}
I'm using iOS 18.2 and Swift 6. Any suggestions on how to correct the bidirectional text rendering?
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 am working on Agora Voice Call and using CallKit to manage incoming and outgoing calls.
Issue:
When I accept a call, CallKit goes behind my app. I want CallKit to remain in front of my app. Please guide me.
In my macOS app I have a SwiftUI list that starts like this:
List(selection: $selection) {
HStack {
Label("Staging", systemImage: "arrow.up.square")
Spacer()
WorkspaceStatusBadge(unstagedCount: model.statusCounts.unstaged,
stagedCount: model.statusCounts.staged)
}
(where WorkspaceStatusBadge is a custom view that just contains a Text)
I'm trying to set the accessibility ID of that first cell so I can find it in XCUITest. If I apply the accessibilityIdentifier() modifier to the HStack, it instead sets the ID of the two static text elements inside it, and the cell still has no ID.
I could find the cell based on the ID of the child staticText, but I have some other cases where this doesn't work as well.
If I use .accessibilityElement() on the HStack, then XCUI sees a cell containing a Group element with the ID. This might be workable, but it's certainly not ideal.
So how do I set the ID of the cell itself?
Suppose there are two buttons in VStack, the second button is unclickable. I'm running macOS 15.2 with Xcode 16.2.
import SwiftUI
struct ContentView: View {
var body: some View {
ScrollView(.horizontal) {
VStack {
Spacer()
// this button is clickable
Button("foo") {
print("foo")
}
// this button can't be clicked
Button("bar") {
print("bar")
}
}
}
}
}
If I change .horizontal -> .vertical and VStack -> HStack, the second button behave normally.
If I remove ScrollView, everything works fine.
it works fine before macOS 15.2.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I want to use Objective C language to implement a button, click the button to achieve the function of Menu Bar - Full Screen Tile - Left of Screen. What should I do? I couldn't find the relevant API.
Topic:
UI Frameworks
SubTopic:
AppKit
I set the isHidden property of a view in traitCollectionDidChange and found that sometime it does not take effect after being set(value of isHidden actually not changed either). It looks like the setting does not take effect when triggered an even number of times, but it is normal when triggered an odd number of times.
When setting isHidden, what actually goes into is [UIView (Rendering) setHidden:], which internally calls [UIView _ bitFlagValueAfterIncrementingHiddenManagement CountForKey: withIncrement: bitFlagValue:] to handle the relevant logic of "_UIViewPendingHiddenCount". Is this issue related to this part of the processing? returning 0 after calling seems normal
This view is a UIStackView, and it is uncertain whether it is related to the type of view
I have an app that acts as an agent (no dock/app, just menu bar icon). When the icon is clicked, I show a popover with a small user interface.
This works great, however, there is an issue. When a certain app is in full-screen and then my menu bar icon is clicked, the user interface shows just fine, until the mouse is moved outside the menu bar - then the user interface stays but the menu bar dismisses and closes.
Is there a way to keep the menu bar open, like when clicking on Control Center, in full-screen apps?
This is how I open my popover:
if let button = statusItem.button {
if popover.isShown {
self.popover.performClose(sender)
} else {
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
popover.contentViewController?.view.window?.makeKey()
}
}
}
Trying to use new Swift @Observable to monitor GPS position within SwiftUI content view. But how do I tie the latest locations to the SwiftUI Map's mapCameraPosition?
Well ideally the answer could cover:
How to fix this error - So get map tracking along with the User Position, but also
How to include facility to turn on/off the map moving to track the user position (which I'll need to do next). So could be tracking, then disable, move map around and have a look at things, then click button to start syncing the mapcameraposition to the GPS location again
Refer to error I'm embedded in the code below.
import SwiftUI
import MapKit
@Observable
final class NewLocationManager : NSObject, CLLocationManagerDelegate {
var location: CLLocation? = nil
private let locationManager = CLLocationManager()
func startCurrentLocationUpdates() async throws {
if locationManager.authorizationStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
for try await locationUpdate in CLLocationUpdate.liveUpdates() {
guard let location = locationUpdate.location else { return }
self.location = location
}
}
}
struct ContentView: View {
var newlocationManager = NewLocationManager()
@State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion(
center: newlocationManager.location?.coordinate ?? <#default value#>,
span: MKCoordinateSpan(latitudeDelta: 0.25, longitudeDelta: 0.25)
))
// GET ERROR: Cannot use instance member 'newlocationManager' within property initializer; property initializers run before 'self' is available
var body: some View {
ZStack {
Map(position: $cameraPosition)
Text("New location manager: \(newlocationManager.location?.description ?? "NIL" )") // works
}
.task {
try? await newlocationManager.startCurrentLocationUpdates()
}
}
}
#Preview {
ContentView()
}
Does anyone have a problem with buttons not clickable in the lists of elements? If I have a list of 30 elements, some of them are clickable and some not. The button is a basic button that prints something in the console. After refresh, click ability is changed but still some clickable and some not. It appears always when compiling with Swift 6. My colleague has the "old" Xcode 15.4 with Swift 5 and when he installs exactly the same code -> buttons and lists work just fine.
I noticed some similar issues with onTapGesture on StackOverflow but my problem is a button. However, I have the same problem with onTapGesture (where I use it) in some of my View components and changing it with highPriorityGesture will not solve the problem since I can't click on the child elements of those Views anymore...
I'm using Xcode 16.2 and iOS 18.2.
Does anyone have an idea how to solve this?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I'm adding Admob ads to my app, and Admob needs to know the width of the view, so I'm using GeometryReader for that. To prevent GeometryReader from grabbing screen space, I've wrapped the main view in GeometryReader { }. I then use geometry.size.width in my call to the adView.
This all works fine. I have two main screens where I show ads, and they both work, until I rotate the device. Then the app crashes!
If I comment out the GeometryReader code and pass a fixed value to the ad view, I can rotate the device with no fear of a crash.
My question is: Do I have to accept that GeometryReader will crash the app when it's rotated, or is there another, stable way to get view dimensions?
Not sure what could cause this. the UI align differently running on iPhone versus running on Mac. If I remove the HStack, it works but I still would like to know why, and if there is a way to make it right on both platforms.
Thank you
here is my code
@State private var viewModel = FirmwareSelectionViewModel()
var body: some View {
Form {
Section("Setup Name") {
TextField ( "", text: $viewModel.setupName )
.foregroundColor(.green )
.disableAutocorrection(true)
.onSubmit {
print ("On Submit")
}
}
Section("Battery") {
HStack() {
Text("Volt")
TextField("", value: $viewModel.Vnominal, format: .number)
.textFieldStyle(.roundedBorder)
.foregroundColor(.green )
#if !os(macOS)
.keyboardType(.decimalPad)
#endif
.onChange(of: viewModel.Vnominal) {
viewModel.checkEntryValidity()
print("Updated Vnominal: \(viewModel.Vnominal)")
}
Text("Ah")
TextField("", value: $viewModel.batteryCapacity, format: .number)
.textFieldStyle(.roundedBorder)
.foregroundColor(.green )
#if !os(macOS)
.keyboardType(.decimalPad)
#endif
.onChange(of: viewModel.batteryCapacity) {
viewModel.checkEntryValidity()
print("Updated Battery Capacity: \(viewModel.batteryCapacity)")
}
}
}
Section("Firmware Type") {
Picker(selection: $viewModel.selectedType, label: EmptyView()) {
ForEach(TypeOfFirmware.allCases) { type in
Text(type.rawValue).tag(type as TypeOfFirmware)
.foregroundColor(.green )
}
}
.pickerStyle(SegmentedPickerStyle())
Picker(selection: $viewModel.selectedFirmware, label: EmptyView()) {
ForEach(viewModel.availableFirmware) { firmware in
Text(firmware.rawValue.capitalized).tag(firmware as Firmware)
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
.onChange(of: viewModel.selectedType) {
viewModel.resetFirmwareSelection()
}
.navigationTitle("Firmware Selection")
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
How to share 'back facing' iOS camera app at same time Eye Tracking app needs 'front facing' camera?
While using my xmas present of a new iPhone and iOS 18.2, I figured I'd try the Eye Tracker app. I've been working with clients successfully using Tobii and other existing eye trackers. In my limited tests, Apple has room for improvement.
My main issue is with the camera app which cannot be used at the same time while using the Eye Tracker app. I get an error popup from Apple:
Camera is use by another app
The image below is from my app showing the popup message "Camera in use by another app", but the same error occurs on the installed camera app. This error is from Apple, not my app.
For terminology: 'front' camera is the one pointing at the user (the selfi camera) while 'back' camera is the main one with multiple lenses. Eye tracking needs the 'front' camera.
It seems when an app uses the camera, it takes over both the front and back facing cameras (since you might swap them). Thus another app, especially Eye Tracking, cannot use just the front facing camera at the same time.
That limits use of Eye Tracking, in particular one cannot take pictures or click any buttons on an app that uses the camera.
Anyone know of a way for an app to not take over both front and back cameras at the same time? If I can separate them, the Eye Tracker could use the front camera while the camera uses the back camera.
Hi,
I'm working on an app that will mostly live in the menu bar.
I'm trying to make a menu item that looks similar to the Tailscale app's menu:
Note: I'm inspired by how Tailscale's menu is rendered:
I have made a View that shows my avatar, name, and optionally the company I work for:
import SwiftUI
struct MenuWhoAmI: View {
var username: String
var binding: String?
var body: some View {
HStack {
AsyncImage(url: URL(string: "https://avatars.githubusercontent.com/u/76716")!){ image in
image.resizable().scaledToFit()
} placeholder: {
ProgressView()
}
.clipShape(Circle())
VStack(alignment: .leading) {
Text(username)
if let binding = binding {
Text("\(binding)").foregroundStyle(.secondary)
}
}
}
}
}
#Preview {
VStack(alignment: .leading) {
MenuWhoAmI(username: "grahamc").padding()
Divider()
MenuWhoAmI(username: "grahamc", binding: "DeterminateSystems").padding()
}.padding()
}
I tried using it in my menu bar:
import SwiftUI
@main
struct DeterminateApp: App {
var body: some Scene {
MenuBarExtra("Determinate", image: "MenuIcon") {
MenuWhoAmI(username: "grahamc")
Button("Two") {}
Button("Three") {}
Divider()
Button("Quit") {
NSApplication.shared.terminate(nil)
}.keyboardShortcut("q")
}.menuBarExtraStyle(.menu)
}
}
and it renders differently:
After reading the forums and documentation, I understood the MenuBarExtra only renders certain elements. I then tried to use an NSStatusBar with an AppDelegate:
import AppKit
import SwiftUI
@main
struct DeterminateApp: App {
@NSApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
Window("Authentication", id: "login") {}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
private var statusItem: NSStatusItem!
func applicationDidFinishLaunching(_ notification: Notification) {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
if let button = statusItem.button {
button.image = NSImage(named: NSImage.Name("MenuIcon"))
}
statusItem.menu = NSHostingMenu(rootView: Group {
Button(action: { print("hi") }) {
MenuWhoAmI(username: "grahamc")
}
})
}
}
and still, the avatar/name doesn't render like I'd expect, missing the circle clipping:
...and I'm a bit mystified.
How can I make this menu render the way I'm trying for?
Thank you!
how to save the state of my APP when I open another APP so that It can restore when I re-open it?
my app will use over 10mb memory so if I open another APP(my app will go background) it will closed at all.
when I re-open it it will restart.
but I do not want it I want if I open Page A and then it go background and when I re-open it it still is Page A and do not restart.
Xcode 16.2 (16C5032a)
FB16300857
Consider the following SwiftData model objects (only the relevant portions are shown) (note that all relationships are optional because eventually this app will use CloudKit):
@Model
final public class Team {
public var animal: Animal?
public var handlers: [Handler]?
...
}
@Model
final public class Animal {
public var callName: String
public var familyName: String
@Relationship(inverse: \Team.animal) public var teams: [Team]?
...
}
@Model
final public class Handler {
public var givenName: String
@Relationship(inverse: \Team.handlers) public var teams: [Team]?
}
Now I want to display Team records in a list view, sorted by animal.familyName, animal.callName, and handlers.first.givenName.
The following code crashes:
struct TeamListView: View {
@Query<Team>(sort: [SortDescriptor(\Team.animal?.familyName),
SortDescriptor(\Team.animal?.callName),
SortDescriptor(\Team.handlers?.first?.givenName)]) var teams : [Team]
var body: some View {
List {
ForEach(teams) { team in
...
}
}
}
}
However, if I remove the sort clause from the @Query and do the sort explicitly, the code appears to work (at least in preliminary testing):
struct TeamListView: View {
@Query<Team> var teams: [Team]
var body: some View {
let sortedTeams = sortResults()
List {
ForEach(sortedTeams) { team in
...
}
}
}
private func sortResults() -> [Team] {
let results: [Team] = teams.sorted { team1, team2 in
let fam1 = team1.animal?.familyName ?? ""
let fam2 = team2.animal?.familyName ?? ""
let comp1 = fam1.localizedCaseInsensitiveCompare(fam2)
if comp1 == .orderedAscending { return true }
if comp1 == .orderedDescending { return false }
... <proceed to callName and (if necessary) handler givenName comparisons> ...
}
}
}
While I obviously have a workaround, this is (in my mind) a serious weakness in the implementation of the Query macro.
In iOS 18, using TextKit to calculate the height of attributed strings is inaccurate. The same method produces correct results in systems below iOS 18.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 40, 100, 0)];
textView.editable = NO;
textView.scrollEnabled = NO;
textView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0);
textView.textContainer.lineFragmentPadding = 0;
textView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:textView];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"陈家坝好吃的撒海程邦达不差大撒把传达是吧才打卡吃吧金卡多措并举哈不好吃大杯茶十八次是吧"];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 4;
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, attributedString.length)];
[attributedString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:NSMakeRange(0, attributedString.length)];
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, attributedString.length)];
textView.attributedText = attributedString;
CGFloat height = [self test:attributedString];
textView.frame = CGRectMake(20, 40, 100, height);
}
- (CGFloat)test:(NSAttributedString *)attString {
// 创建 NSTextStorage 并设定文本内容
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attString];
// 创建 NSLayoutManager 并关联 NSTextStorage
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
// 创建 NSTextContainer 并设定其属性
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(100, CGFLOAT_MAX)];
textContainer.lineFragmentPadding = 0;
[layoutManager addTextContainer:textContainer];
// 强制布局管理器计算布局
[layoutManager ensureLayoutForTextContainer:textContainer];
// 获取文本内容所占的高度
CGFloat height = [layoutManager usedRectForTextContainer:textContainer].size.height;
// 返回四舍五入高度
return ceil(height);
}
If two NavigationStacks are nested with the inner stack in a sheet NavigationLinks in the inner stack open as expected in the inner stack.
struct ContentView: View {
var body: some View {
NavigationStack {
Color.clear
.sheet(isPresented: .constant(true)) {
NavigationStack {
ExampleList()
.navigationTitle("Inner Navigation Stack")
}
.presentationDetents([.medium])
}
.navigationTitle("Outer Navigation Stack")
}
}
}
If I try the same with an overlay instead of a sheet, NavigationLinks in the inner stack unexpectedly open in the outer stack.
struct ContentView: View {
var body: some View {
NavigationStack {
Color.clear
.overlay(alignment: .bottomTrailing) {
NavigationStack {
ExampleList()
.navigationTitle("Inner Navigation Stack")
}
.frame(width: 200, height: 250)
.border(.black, width: 5)
.padding()
.presentationDetents([.medium])
}
.navigationTitle("Outer Navigation Stack")
}
}
}
Even the navigation title for the outer stack is being overridden by the inner stack's navigation title.
TLDR
What magic is sheet using that allows for nested NavigationStacks and how might I approach getting this to work in an overlay?
iOS 18.2
Xcode 16.2
The definition of ExampleList for reproducibility:
struct ExampleList: View {
var body: some View {
List(1..<5) { number in
NavigationLink("\(number)") {
Text("\(number)")
.font(.largeTitle)
}
}
}
}
Its important to note that this same app did not have this issue in iOS 17.
Ever since iOS 18 I have noticed that when application written in SwiftUI uses Label with the default color (which auto changes between light and dark appearance), from time to time when resuming an application that has been in the background, the color of those labels (only the Label elements) switches from the opposite to the correct one. Here is an example:
Steps to reproduce
Phone is in dark appearance
Open app
Labels text color is white and labels background is black
Go to home so that app is on background
Wait random time (does not happen all the time), some times 1 min some times 10
Reopen the application.
During the opening transition the Label text color was changed while the app was in suspended mode to the light appearance variant (black)
Once the app opening transition finishes the Label text color switches back to the correct color for dark appearance (white)
Same issue happens if you start from light appearance. I cannot reproduce this on Xcode simulators, I have tried to force memory warning to check if that has anything to do with it but that also does not cause the issue to appear on simulators. For now I can only reproduce this on real device.
Screenshots
Here is screenshots of the above example:
During transition
After transition
Topic:
UI Frameworks
SubTopic:
SwiftUI
My SwiftUI app uses an Image with a tap gesture:
Image(systemName: "xmark.circle.fill")
.accessibilityIdentifier(kTextFieldClearButton)
.foregroundColor(.secondary)
.padding(.trailing, 6)
.onTapGesture {
dataSource.textFieldText = ""
}
In a UI test, I want to tap this image to execute its action:
let clearButton = app.images[kTextFieldClearButton]
clearButton.tap()
However the action is not executed.
I then set a breakpoint at clearButton.tap(), to execute lldb commands. Here are the results:
(lldb) p clearButton.isHittable
t = 439.54s Find the "TextFieldClearButton" Imag
(Bool) true
e
It is a little strange that "Image" has been interrupted by (Bool) true, but the image is hittable.
p clearButton.isAccessibilityElement
gives
(lldb) p clearButton.isAccessibilityElement
(Bool) false
I don't understand why this Image is no accessibility element. I thought, SwiftUI Views are by default accessible.
What can I do to make it accessible so that clearButton.tap() works as expected?
After the user clicks the Open button in the AppClip card, the AppClip launches, but the card keeps appearing whenever the user clicks Open. It doesn’t disappear until the user clicks the Close button on the card.
This issue started appearing two months ago and only occurs on iOS 17.6 and 17.7.
[demo video](https://drive.google.com/file/d/1vJ-7E5JSdO_xoVkDYxBJDkj8sm-dvxv1/view?usp=share_link
Topic:
UI Frameworks
SubTopic:
General