To change the background of a TextField, I simply apply:
TextField("0.0", value: $p, format: .number)
.textFieldStyle(PlainTextFieldStyle())
.background(.red)
That does only work with plain style, but it works.
Trying something similar on a button changes the container view background.
The only solution I've found is to overlap with a Rectangle.
How is it ?
A SwiftUI bug ?
A current limit of Swift ?
A rationale for it ?
There a better solution I've not found ?
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi everyone,
I need to synchronize the playback of RealityKit Timelines via SharePlay.
To do this I am trying to get the references of the timelines using "AnimationPlaybackController" and "AnimationResource". In my realitykit scene I have configured both an animation (with blender), and a timeline, the animation starts correctly when the realitykit scene starts, the timeline not.
Below the code:
struct ContentView: View {
@State private var subscriptions = [EventSubscription]()
@Environment(AppModel.self)
private var appModel
let rootEntity = Entity()
@State var testEntity: Entity?
@State var testAnimation: AnimationResource?
@State var testController: AnimationPlaybackController?
init() {
CubeComponent.registerComponent()
}
var body: some View {
RealityView { content in
content.add(rootEntity)
if let scene = try? await Entity(named: "Room", in: realityKitContentBundle) {
rootEntity.addChild(scene)
playAnimations(from: content)
}
}
.gesture(SpatialTapGesture().targetedToAnyEntity()
.onEnded({ value in
_ = value.entity.applyTapForBehaviors()
if let testEntity, let testAnimation {
testController = testEntity.playAnimation(testAnimation.repeat())
}
})
)
}
func playAnimations(from content: RealityViewContent) {
subscriptions.append(content.subscribe(to: ComponentEvents.DidAdd.self, componentType: AnimationLibraryComponent.self, { event in
let entity = event.entity
entity.components[AnimationLibraryComponent.self]?.animations.forEach({ (key, value) in
if value.definition is AnimationGroup {
if key == "/Room/TestTimeline" {
let controller = entity.playAnimation(value.repeat())
testEntity = entity
testAnimation = value
appModel.syncronizedAnimations[key] = .init(name: key, animationController: controller, entityName: entity.name)
}
} else {
if entity.name == "SphereInteractable" {
let controller = entity.playAnimation(value.repeat())
appModel.syncronizedAnimations[key] = .init(name: key, animationController: controller, entityName: entity.name)
}
}
})
}))
}
}
the variables testEntity, testAnimation and testController are for testing purposes only. If I try to start the animations in the playAnimations function, only the animation created via blender starts (the one related to the object "SphereInteractable"), the Timeline starts only if I save a reference and I play it with a tap gesture or with a delay of ! seconds with DispatchQueue.asyncAfter called in the onAppear.
is there a better way to handle this? The goal is to have a reference of the AnimationPlaybackController of the timeline, in order to sync the animation via shareplay.
Thanks
Hello community,
I'm an iOS developer from VW group, I was doing some proof of concepts around an automaker app, and I've found a big blocker. When I was trying to summon a keyboard, it wasn't displayed.
So is it even possible?
Do I have to do some workaround with Carplay templates in order to be able to have the native keyboard from Carplay, or is there a special component that I need to introduce in my code to summon the keyboard?
Thank you very much.
David Cosialls.
I've been obsessed with this topic for the past couple of weeks and unfortunately there just isn't a good answer out there even from the community. Therefore I am hoping that I can summon Quinn to get an official Apple position (on what's seemingly a fairly fundamental part of using SwiftUI).
Consider this simple example:
import Foundation
@MainActor
@Observable
class UserViewModel {
var name: String = "John Doe"
var age: Int = 30
// other properties and logic
}
// NetworkManager does not need to update the UI but needs to read/write from UserViewModel.
class NetworkManager {
func updateUserInfo(viewModel: UserViewModel) {
Task {
// Read values from UserViewModel prior to making a network call
let userName: String
let userAge: Int
// Even for a simple read, we have to jump onto the main thread
await MainActor.run {
userName = viewModel.name
userAge = viewModel.age
}
// Now perform network call with the retrieved values
print("Making network call with userName: \(userName) and userAge: \(userAge)")
// Simulate network delay
try await Task.sleep(nanoseconds: 1_000_000_000)
// After the network call, we update the values, again on the main thread
await MainActor.run {
viewModel.name = "Jane Doe"
viewModel.age = 31
}
}
}
}
// Example usage
let viewModel = UserViewModel()
let networkManager = NetworkManager()
// Calling from some background thread or task
Task {
await networkManager.updateUserInfo(viewModel: viewModel)
}
In this example, we can see a few things
The ViewModel is a class that manages states centrally
It needs to be marked as MainActor to ensure that updating of the states is done on the main thread (this is similar to updating @Published in the old days). I know this isn't officially documented in Apple's documentation. But I've seen this mentioned many times to be recommended approach including www.youtub_.com/watch?v=4dQOnNYjO58 and here also I have observed crashes myself when I don't follow this practise
Now so far so good, IF we assume that ViewModel are only in service to Views. The problem comes when the states need to be accessed outside of Views.
in this example, NetworkManager is some random background code that also needs to read/write centralized states. In this case it becomes extremely cumbersome. You'd have to jump to mainthread for each write (which ok - maybe that's not often) but you'd also have to do that for every read.
Now. it gets even more cumbersome if the VM holds a state that is a model object, mentioned in this thread..
Consider this example (which I think is what @Stokestack is referring to)
import Foundation
// UserModel represents the user information
@MainActor // Ensuring the model's properties are accessed from the main thread
class UserModel {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
@MainActor
@Observable
class UserViewModel {
var userModel: UserModel
init(userModel: UserModel) {
self.userModel = userModel
}
}
// NetworkManager does not need to update the UI but needs to read/write UserModel inside UserViewModel.
class NetworkManager {
func updateUserInfo(viewModel: UserViewModel) {
Task {
// Read values from UserModel before making a network call
let userName: String
let userAge: Int
// Jumping to the main thread to safely read UserModel properties
await MainActor.run {
userName = viewModel.userModel.name
userAge = viewModel.userModel.age
}
// Simulate a network call
print("Making network call with userName: \(userName) and userAge: \(userAge)")
try await Task.sleep(nanoseconds: 1_000_000_000)
// After the network call, updating UserModel (again, on the main thread)
await MainActor.run {
viewModel.userModel.name = "Jane Doe"
viewModel.userModel.age = 31
}
}
}
}
// Example usage
let userModel = UserModel(name: "John Doe", age: 30)
let viewModel = UserViewModel(userModel: userModel)
let networkManager = NetworkManager()
// Calling from a background thread
Task {
await networkManager.updateUserInfo(viewModel: viewModel)
}
Now I'm not sure the problem he is referring still exists (because I've tried and indeed you can make codeable/decodables marked as @Mainactor) but it's really messy.
Also, I use SwiftData and I have to imagine that @Model basically marks the class as @MainActor for these reasons.
And finally, what is the official Apple's recommended approach? Clearly Apple created @Observable to hold states of some kind that drives UI. But how do you work with this state in the background?
Hi,
Im trying to use ForEach without list to get rid of the navigation chevron , but the sipe to delete modifier stop working, is there a some solution ?
Kind Regards
Button(role: .destructive) {
deletePatient(patient: patient)
} label: {
VStack {
Label("Delete", systemImage: "trash")
Image(systemName: "Trash")
}
}
}
I used standard font styles in an iOS app. For example .font(.headline). I hoped that developing this way would allow the adoption of the app to other platforms, relatively easy.
However, when trying to run for iPadOS, the text did not increase in size to occupy the more abundant space offered by larger screen, but it actually shrank. Overall, the app does not look great "automatically".
Why does it happen?
What is the best practice for cross platform development with SwiftUI (with regards to font sizes). I want to make as little as possible human interface design decisions on my own and just let SwiftUI take care of everything. (But I also want the results to look as Apple would consider great looking)
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?
Does anyone have any idea why withAnimation is buggy when you apply a clip shape to an image? I've attached a screenshot of what happens below. Sometimes when hovering, it looks like the item gets drawn at the wrong location for a frame or two and then is placed back into position and the animation starts. It doesn't happen when the hover state ends, only the very initial hover event. This also doesn't happen without the .clipShape. I've also tried using .mask, but the same issue occurs. Has anyone ran into this?
When first opening my app, the first view navigated to loads and then a second later reloads. When navigating away and back to the view, it only loads once as designed.
Has anyone ever experienced this before and knows of any obvious reasons?
I can upload code snippets later, the views are wrapped in navigation links.
Thanks for any help
I'm wondering if there is a way to force a re-fetch of a @Query property inside of a SwiftUI view so I could offer a pull-to-refresh mechanism for users to force-refresh a view.
Why would I want this?
iOS 18.0 and 18.1 currently contain some regressions that prevent SwiftData from properly gathering model updates caused by ModelActor's running on background threads and the suggested workarounds (listening for .NSManagedObjectContextDidSave) don't work well in most scenarios and do not cause queries in the current view to be fully re-evaluated (see Importing Data into SwiftData in the Background Using ModelActor and @Query).
On visionOS, I have discovered that if dismissWindow is followed immediately by a call to openWindow, the new window does not open where the user is looking at. Instead, it appears at the same location as the dismissed window. However, if I open the new window after a small delay, or after UIScene's willDeactivateNotification, the new window correctly opens in front of the user. (I tested this within a opened immersive space.)
Does this imply that dismissWindow is actually asynchronous, in the sense that it requires extra time to reset certain internal states before the next openWindow can be called? What is the best practice to close a window, then open a new window in front of the user's current head position?
I’m trying to use TabView as a page view, but I’m having some trouble. When I select a tab, the content gets cut off. I tried setting scrollClipDisabled, but that didn’t help.
var body: some View {
TabView {
Button {
} label: {
AsyncImage(
url: URL(
string:
"https://plus.unsplash.com/premium_photo-1693227521269-d90b70e3ee06?q=80&w=2940&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
)
) { image in
image
.resizable()
.aspectRatio(contentMode: .fit)
} placeholder: {
Color.red
}
}
.buttonStyle(.borderless)
}
.scrollClipDisabled()
.tabViewStyle(.page(indexDisplayMode: .always))
.indexViewStyle(.page(backgroundDisplayMode: .always))
Button("Button") {
}
}
If you switch between tab content and the button, you will notice that the bottom corner radius is clipped.
Does anyone have any idea how to avoid this action?
I have a working ValueTransformer that runs fine in simulator/device, but crashes in SwiftUI Preview. Even though they are the same code.
Here is my code
import Foundation
final class StringBoolDictTransformer: ValueTransformer {
override func transformedValue(_ value: Any?) -> Any? {
guard let stringBoolDict = value as? [String: Bool] else { return nil }
let nsDict = NSMutableDictionary()
for (key, bool) in stringBoolDict {
nsDict[key] = NSNumber(value: bool)
}
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: nsDict, requiringSecureCoding: true)
return data
} catch {
debugPrint("Unable to convert [Date: Bool] to a persistable form: \(error.localizedDescription)")
return nil
}
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else { return nil }
do {
guard let nsDict = try NSKeyedUnarchiver.unarchivedDictionary(ofKeyClass: NSString.self, objectClass: NSNumber.self, from: data) else {
return nil
}
var result = [String: Bool]()
for (key, value) in nsDict {
result[key as String] = value.boolValue
}
return result
} catch {
debugPrint("Unable to convert persisted Data to [Date: Bool]: \(error.localizedDescription)")
return nil
}
}
override class func allowsReverseTransformation() -> Bool {
true
}
override class func transformedValueClass() -> AnyClass {
NSDictionary.self
}
}
and here is the container
public struct SwiftDataManager {
public static let shared = SwiftDataManager()
public var sharedModelContainer: ModelContainer
init() {
ValueTransformer.setValueTransformer(
StringBoolDictTransformer(), forName: NSValueTransformerName("StringBoolDictTransformer")
)
let schema = Schema([,
Plan.self
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
sharedModelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}
}
and the model
@Model
final class Plan {
@Attribute(.transformable(by: StringBoolDictTransformer.self))
var dict: [String: Bool] = [:]
}
I would get that container and pass it in appdelegate and it works fine. I would get that container and pass it inside a #Preview and it would crash with the following:
Runtime: iOS 17.5 (21F79) - DeviceType: iPhone 15 Pro
CoreFoundation:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "dict"; desired type = NSDictionary; given type = _NSInlineData; value = {length = 2, bytes = 0x7b7d}.'
libsystem_c.dylib:
abort() called
Version 16.0 (16A242d)
Hey there,
Is there a way to launch another view by tapping on the preview of a context menu? Something like the behavior of the Photos app where tapping on the preview navigates to the details view.
Tap gesture handlers on the preview don't seem to get called, even as high priority gestures.
Thanks for the help!
Gab
I've got another issue with Gesture.updating(_:body:).. This looks a bit like this thread, but it's different. My problem occurs when creating a simultaneous gesture combining a RotateGesture with a MagnifyGesture.
struct ManipulationState: Equatable {
var magnification: CGFloat?
var rotation: Angle?
}
@GestureState var state: ManipulationState? = nil
var gesture: GestureStateGesture<SimultaneousGesture<RotateGesture, MagnifyGesture>, ManipulationState?> {
SimultaneousGesture(
RotateGesture(minimumAngleDelta: .degrees(5)),
MagnifyGesture(minimumScaleDelta: 0.1)
)
.updating($state) { value, state, transaction in
state = ManipulationState(
magnification: value.second?.magnification,
rotation: value.first?.rotation
)
}
}
When rotating and magnifying quite a bit, at some point, something happens, the gesture stops working altogether and the state never resets to the initial value any more.
When adding an onChange handler to some view in the body, you can watch state never gets nil again.
.onChange(of: state, { oldValue, newValue in
print("\(oldValue) \(newValue)")
})
I noticed the same happening when using ExclusiveGesture instead of SimultaneousGesture.
Full code example here: https://github.com/teameh/GestureIssueTester/blob/main/GestureTester/ContentView.swift
Video demonstrating issue here: https://github.com/teameh/GestureIssueTester/raw/refs/heads/main/screen-recording.mov
I've tried using Gesture.onChanged(_:) and Gesture.onEnded(_:)as well, butonEnded` is also not always called.
Is there anyone here who ran into the same problem or perhaps someone can share tips on a workaround or a fix?
Tested using Xcode 16.0 (16A242d)
In WWDC 2023 there was a good summary of how to handle the iOS 17 Observation capability.
But despite the clear graphics, it was still ambiguous (for me.)
I want to inject a class (view-model) so that it can be used in the complete view heirarchy, and used in bindings to allow bi-directional communication.
As far as I can tell there are 2 ways of declaring the VM (alternatives 1 and 2 in my code), and 2 ways of consuming the VM in a view (alternatives 3 and 4 in my code). Using the flow-diagram I can't determine which is best.
Here's the crux of my #Observable problem.
import SwiftUI
// MARK: - Model
struct MyMod {
var title = "Hello, World!"
}
// MARK: - MVV
@Observable
class MyMVV {
var model: MyMod
init() {
self.model = MyMod()
}
}
// MARK: - App
@main
struct MyApp: App {
@Bindable var myGlobalMVV = MyMVV() // Alternative 1
// @State var myGlobalMVV = MyMVV() // Alternative 2
var body: some Scene {
WindowGroup {
ContentView()
.environment(myGlobalMVV) // inject
}
}
}
struct ContentView: View {
var body: some View {
ContentDeepHierarchyView()
}
}
struct ContentDeepHierarchyView: View {
@Environment(MyMVV.self) var myGlobalMVV // digest
var body: some View {
@Bindable var myLocalMVV = myGlobalMVV // Alternative 3
TextField("The new title", text: $myLocalMVV.model.title) // Alternative 3
TextField("The new title", text: Bindable(myGlobalMVV).model.title) // Alternative 4
}
Opinions?
I am creating a LazyVGrid with 2 columns. I want it so that if there is only one item in a row, then it goes to the center of the row. I tried using an HStack with a Spacer, but it doesn't push it to the center. How do I do it?
ForEach(pets) { pet in
VStack {
Image(pet.species.rawValue)
.resizable()
.frame(width: 80, height: 80)
Text(pet.name)
.poppinsBold(size: 16)
}
}
HStack {
if pets.hasEvenNumber {
Spacer(minLength: 0)
}
Button {
addPetSheet = true
} label: {
VStack {
ZStack {
Circle()
.frame(width: 70, height: 70)
.foregroundStyle(.gray)
Image(systemName: "plus")
.foregroundStyle(.white)
.font(.title)
}
Text("Add")
.poppinsBold(size: 16)
}
}
}
}
We seen to have found an issue when using the pushWindow action on visionOS. The issue occurs if the app is backgrounded then reopened by selecting the apps icon on the home screen. Any window that is opened via the pushWindow action is then dismissed. We've been able to replicate the issue in a small sample project.
Replication steps
Open app
Open window via the push action
Press the digital crown
On the home screen select the apps icon again
The pushed window will now be dismissed.
There is a sample project linked here that shows off the issue, including a video of the bug in progress
I have a view containing either a TextField or a SecureField. I'm hoping I can use a single FocusState value that will apply to either the TextField or SecureField. (I'm using FocusState to ensure the cursor will be in the field when it initially loads)
I've verified this works in a sample project when the view is in a WindowGroup. But when I instead use a DocumentGroup ~50% of the time when the view loads/launches, it does not have focus.
Here is my ContentView:
struct ContentView: View {
let coinFlip: Bool = .random() // used to choose between the TextField and the SecureField
@State var fieldContent: String = "" // bound to the Field value
@FocusState var focus: Bool
var body: some View {
VStack {
Text("Coin Flip: \(coinFlip)")
actualField
.focused($focus, equals: true)
}
.onAppear() {
focus = true
}
}
@ViewBuilder var actualField: some View {
if coinFlip {
TextField("Enter text here", text: $fieldContent)
} else {
SecureField("Enter secure text here", text: $fieldContent)
}
}
}
and here is my App swift file
@main
struct ModernTurtleApp: App {
var body: some Scene {
// WindowGroup {
// ContentView()
// }
DocumentGroup(newDocument: ModernTurtleDocument()) { file in
ContentView()
}
}
}
When this code runs, the Field has focus about 50% of the time on initial launch. When I uncomment the WindowGroup and comment the DocumentGroup, the field always has focus on initial launch.
I realize I can work around this behaviour by using an optional enum for FocusState. I would be ok going this route, but I first want to try to understand the behaviour I'm seeing, and possibly keep my simpler FocusState implementation.
Thanks, in advance for any help.
I think I have the simplest possible Mac app trying to see if I can have VideoPlayer work in an Xcode Preview. It works in an iOS app project. In a Mac app project it builds and runs. But if I preview in Xcode it crashes.
The diagnostic says:
| [Remote] Unknown Error: The operation couldn’t be completed. XPC error received on message reply handler
|
| BSServiceConnectionErrorDomain (3):
| ==NSLocalizedFailureReason: XPC error received on message reply handler
| ==BSErrorCodeDescription: OperationFailed
The code I'm using is the exact code from the VideoPlayer documentation page. See this link.
Any ideas about this XPC error, and how to work around?
I'm using Xcode 16.0 on macOS 14.6.1