I have this code to make ARVR Stereo View To Be Used in VR Box Or Google Cardboard, it uses iOS 18 New RealityView but for some reason the left side showing the Entity (Box) more near to the camera than the right side which make it not identical, I wonder is this a bug and need to be fixed or what ? thanx
Here is the code
import SwiftUI
import RealityKit
struct ContentView : View {
let anchor1 = AnchorEntity(.camera)
let anchor2 = AnchorEntity(.camera)
var body: some View {
HStack (spacing: 0){
MainView(anchor: anchor1)
MainView(anchor: anchor2)
}
.background(.black)
}
}
struct MainView : View {
@State var anchor = AnchorEntity()
var body: some View {
RealityView { content in
content.camera = .spatialTracking
let item = ModelEntity(mesh: .generateBox(size: 0.25), materials: [SimpleMaterial()])
anchor.addChild(item)
content.add(anchor)
anchor.position.z = -1.0
anchor.orientation = .init(angle: .pi/4, axis:[0,1,1])
}
}
}
And Here is the View
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
Hello, I've created an app that follows the user as they navigate through public transport.
I want the camera to follow the user and at the same time I want the camera distance (elevation) to change dynamically depending on speed and other factors.
I've tried a first approach using camera keyframes, but I've noticed a lot of crashes when the app comes back to the foreground.
.mapCameraKeyframeAnimator(trigger: cameraFrame) { camera in
KeyframeTrack(\MapCamera.centerCoordinate) {
LinearKeyframe(cameraFrame.center, duration: cameraFrame.duration, timingCurve: cameraFrame.curve)
}
KeyframeTrack(\MapCamera.distance) {
LinearKeyframe(cameraFrame.distance, duration: cameraFrame.duration, timingCurve: cameraFrame.curve)
}
}
Some logs mention wrong center coordinates (nan, nan) but when I print them, it's show me valid coordinates.
I've also tried manually setting the camera for each position update, but the result is not smooth.
position = .camera(
.init(.init(
lookingAtCenter: newPosition,
fromDistance: cameraElevation,
pitch: .zero,
heading: .zero)
)
)
What's the best way to achieve this?
Hi, I have the view below that I want it to get any sort of SwiftData model and display and string property of that module, but I get the error mentioned below as well, also the preview have an error as below, how to fix it ? I know its little complicated.
Error for the view GWidget
" 'init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable "
Error of preview
" Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder' "
3, Code
#Preview {
do {
let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(for: Patient.self, configurations: configuration)
let example = Patient(firstName: "Ammar S. Mitoori", mobileNumber: "+974 5515 7818", homePhone: "+974 5515 7818", email: "ammar.s.mitoori@gmail.com", bloodType: "O+")
// Pass the model (Patient) and the keyPath to the bloodType property
return GWidget(model: example, keyPath: \Patient.bloodType)
.modelContainer(container)
} catch {
fatalError("Fatal Error")
}
}
4. Code for the Gwidget View
```import SwiftUI
import SwiftData
struct GWidget<T>: View {
@Bindable var model: T
var keyPath: KeyPath<T, String> // Key path to any string property
// Variables for the modified string and the last character
var bloodTypeWithoutLast: String {
let bloodType = model[keyPath: keyPath]
return String(bloodType.dropLast())
}
var lastCharacter: String {
let bloodType = model[keyPath: keyPath]
return String(bloodType.suffix(1))
}
var body: some View {
VStack(alignment: .leading) {
Text("Blood Type")
.font(.footnote)
.foregroundStyle(sysPrimery07)
HStack (alignment: .lastTextBaseline) {
Text(bloodTypeWithoutLast)
.fontWeight(.bold)
.font(.title2)
.foregroundStyle(sysPrimery07)
VStack(alignment: .leading, spacing: -5) {
Text(lastCharacter)
.fontWeight(.bold)
Text(lastCharacter == "+" ? "Positive" : "Negative")
}
.font(.caption2)
.foregroundStyle(lastCharacter == "+" ? .green : .pink)
}
}
}
}
Hi
When connecting a SwiftData module property to a SwiftUI view such as a text field and the field changes by user the property get updated in the SwiftData database, now suppose I want to run a validation code or delay updates to Database till use click a submit button how to do that ? delay those auto updates if we can name it ?
Kind Regards
Code Example
import SwiftUI
import SwiftData
struct GListSel2: View {
@Bindable var patient: Patient
var body: some View {
HStack {
TextField("Gender", text: $patient.gender)
}
}
}
I made a LockScreen ControlWidget with CameraCaptureIntent, but I found launch my main app from Control Widget, SceneDelegate will be called like below:
sceneWillEnterForeground
sceneDidBecomeActive
sceneWillResignActive
sceneDidBecomeActive
sceneWillResignActive be called, is it normal?
it make my app camera launch with a delay.
Hi,
When passing a SwftData Module to a view that receives it in a @Binadable property variable I get an error that it doesn't conform to Observation, I don't know how to solve this issue, even adding @Observable type to the generic in the structure definition won't solve it, any suggestions ?
Kind Regards
I have drag-and-drop functionality in the macOS app built with SwiftUI.
Since macOS 15 there is an issue with it, because as I found out, the completion block of loadObject method on NSItemProvider is not called until dropExited delegate method is called (see simplified code example below).
It causes very strange behavior in my app, for one of the most important features, and I am looking for a way to fix it as soon as possible.
Is anyone seeing the same issue?
I saw there was a bug with drag and drop on iOS 18, which seems to be fixed in 18.1. Anyone from Apple can say anything about this change in behaviour?
@Observable // Because it is injected via environment.
final class DragAndDropDelegate<T: Codable>: DropDelegate {
func dropEntered(info: DropInfo) {
// Is called as expected.
guard
let itemProvider = info.itemProviders(for: [UTType.data]).first
else { return }
itemProvider.loadObject(ofClass: DraggableObject<T>.self) { [weak self] (object, error) in
// This is only called after dropExited delegate method is called !!!
// Before macOS 15.0 it is called quickly after the loadObject method invokation.
asyncOnMainThread {
guard
let self,
let draggableObject = object as? DraggableObject<T>
else { return }
self.onEnter?(draggableObject.object, info.location)
}
}
}
func dropExited(info: DropInfo) {
// Is called as expected.
}
}
I've run into an issue with my app that I've been able to narrow down to a small reproducer.
Any time there is a task associated with the DetailView and you "pop to top", onAppear is called again and the task is re-run. Why is that? Is this a SwiftUI bug? It doesn't happen on iOS 17, only 18.
import SwiftUI
@Observable
class Store {
var shown: Bool = true
}
@main
struct MyApp: App {
@State private var store = Store()
var body: some Scene {
WindowGroup {
if store.shown {
ContentView()
} else {
EmptyView()
}
}
.environment(store)
}
}
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DetailView()) {
Text("Go to Detail View")
}
}
}
}
struct DetailView: View {
@Environment(Store.self) private var store
init() {
print("DetailView initialized")
}
var body: some View {
Button("Pop to top") {
store.shown = false
}
.task {
print("DetailView task executed")
}
.onAppear {
print("DetailView appeared")
}
.onDisappear {
print("DetailView disappeared")
}
}
}
Hello!
Is there any way to detect when the animation appearing in iOS 18 on switching tab items completes? This applies to TabView in SwiftUI.
I used to be able to display all app icon assets in the UI using UIImage(named: String)
However, it seems this method has been deprecated in Xcode 16 and the iOS 18.
How can I display app icon assets in the UI now, without duplicating the assets?
Hi,
In this year WWDC 2024 conference a new update to SwiftData allows it to connect to other kind of data sources or databases, at ;east this is what I understood, since then didn't see any tutorial or help document on how to do that for example connecting SwiftData to Firebase if possible ?
Kind Regards
I have a Map in SwiftUI using MapKit and the map has several annotations and MapCircles added to it. I need to have the ability to center the map on a specific latitude and longitude. The issue is that the map instead is centering so that all annotations and MapCircles etc. are visible.
How can I have it disregard items added to the map and center the map at a specific latitude and longitude and ideally, control the zoom level of the map also?
Our company has developed a product available, which measures body composition. During the measurement process, lasting 40 seconds, we require the device screen to remain illuminated. We are actively using the "Always On" feature and have set the timer on the watch to 70 minutes to prevent the screen from dimming.
However, we are encountering issues where the screen may still turn off during the measurement. Could you please provide guidance on how to keep the screen active with backlighting across all Apple Watch models during measurements?
I figured it would be as simple as changing the selection variable back to nil, but that seemingly has no effect. The Table row stays selected, and if I press on it again, it won't trigger my .navigationDestination(). How can I resolve this? I found another post asking the same thing, with no resolution. The only way I can clear it is by clicking with my mouse somewhere else.
@State private var selectedID: UUID? = nil
Table(tableData, selection: $selectedID, sortOrder: $sortOrder)...
.navigationDestination(item: $selectedID, destination: { id in
if let cycle = cycles.first(where: {$0.id == id}) {
CycleDetailView(cycle: cycle)
.onDisappear(perform: {
selectedID = nil
})
}
})
I've got a List containing Colour objects. Each colour may have an associated Project Colour object.
What I'm trying to do is set it up so that you can tap a cell and it will add/remove a project colour.
The adding/removing is working, but each time I do so, it appears the whole view is reloaded, the scroll position is reset and any predicate is removed.
This code I have so far
List {
ForEach(colourList) { section in
let header : String = section.id
Section(header: Text(header)) {
ForEach(section) { colour in
HStack {
if checkIfProjectColour(colour: colour) {
Image(systemName: "checkmark")
}
VStack(alignment: .leading){
HStack {
if let name = colour.name {
Text(name)
}
}
}
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
if checkIfProjectColour(colour: colour) {
removeProjectColour(colour: colour)
} else {
addProjectColour(colour: colour)
}
}
}
}
}
.onAppear() {
filters = appSetting.filters
colourList.nsPredicate = getFilterPredicate()
print("predicate: on appear - \(String(describing: getFilterPredicate()))")
}
.refreshable {
viewContext.refreshAllObjects()
}
}
.searchable(text: $searchText)
.onSubmit(of: .search) {
colourList.nsPredicate = getFilterPredicate()
}
.onChange(of: searchText) {
colourList.nsPredicate = getFilterPredicate()
}
The checkIfProjectColour function
func checkIfProjectColour(colour : Colour) -> Bool {
if let proCols = project.projectColours {
for proCol in proCols {
let proCol = proCol as! ProjectColour
if let col = proCol.colour {
if col == colour {
return true
}
}
}
}
return false
}
and the add/remove functions
func addProjectColour(colour : Colour) {
let projectColour = ProjectColour(context: viewContext)
projectColour.project = project
projectColour.colour = colour
colour.addToProjectColours(projectColour)
project.addToProjectColours(projectColour)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
func removeProjectColour(colour: Colour) {
if let proCols = project.projectColours {
for proCol in proCols {
let proCol = proCol as! ProjectColour
if let col = proCol.colour {
if col == colour {
viewContext.delete(proCol)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
}
}
This has been broken for over 5 years now. I see 2 different behaviors in 2 different SwiftUI apps. This makes SwiftUI not ready for prime time apps, but I just have tools right now.
The VStack { List } doesn't scroll to the item in a long list. The selection moves to the next item in the list, but can't see it. This is just basic UI functionality of a list. UIListView doesn't have this issue.
The NavigationView { List { NavigationLink }} wraps around back to the top of the list when pressing down arrow past the last visible item, but there are plenty more list items to visit.
If I drag something into my SwiftUI Mac app the .dropDestination gets an array of URLs that I can do with what I want.
If I use .fileImporter to get an identical array of URLs I should wrap start/stop securityScopedResource() calls around each URL before I do anything with it.
Can anyone explain the logic behind that? Is there some reason I'm not seeing? It is especially annoying in that the requirement for security scoping also doesn't exist if I use an NSOpenPanel instead of .fileImporter.
I have an immersive space with a RealityKit view which is running an ARKitSession to access main camera frames.
This frame is processed with custom computer vision algorithms (and deep learning models).
There is a 3D Entity in the RealityKit view which I'm trying to place in the world, but I want to debug my (2D) algorithms in an "attached" view (display images in windows).
How to I send/share data or variables between the views (and and spaces)?
In creating a sequenced gesture combining a LongPressGesture and a DragGesture, I found that the combined gesture exhibits two problems:
The @GestureState does not properly update as the gesture progresses through its phases. Specifically, the updating(_:body:) closure (documented here) is only ever executed during the drag interaction. Long presses and drag-releases do not call the updating(_:body:) closure.
Upon completing the long press gesture and activating the drag gesture, the drag gesture remains empty until the finger or cursor has moved. The expected behavior is for the drag gesture to begin even when its translation is of size .zero.
This second problem – the nonexistence of a drag gesture once the long press has completed – prevents access to the location of the long-press-then-drag. Access to this location is critical for displaying to the user that the drag interaction has commenced.
The below code is based on Apple's example presented here. I've highlighted the failure points in the code with // *.
My questions are as follows:
What is required to properly update the gesture state?
Is it possible to have a viable drag gesture immediately upon fulfilling the long press gesture, even with a translation of .zero?
Alternatively to the above question, is there a way to gain access to the location of the long press gesture?
import SwiftUI
import Charts
enum DragState {
case inactive
case pressing
case dragging(translation: CGSize)
var isDragging: Bool {
switch self {
case .inactive, .pressing:
return false
case .dragging:
return true
}
}
}
struct ChartGestureOverlay<Value: Comparable & Hashable>: View {
@Binding var highlightedValue: Value?
let chartProxy: ChartProxy
let valueFromChartProxy: (CGFloat, ChartProxy) -> Value?
let onDragChange: (DragState) -> Void
@GestureState private var dragState = DragState.inactive
var body: some View {
Rectangle()
.fill(Color.clear)
.contentShape(Rectangle())
.onTapGesture { location in
if let newValue = valueFromChartProxy(location.x, chartProxy) {
highlightedValue = newValue
}
}
.gesture(longPressAndDrag)
}
private var longPressAndDrag: some Gesture {
let longPress = LongPressGesture(minimumDuration: 0.2)
let drag = DragGesture(minimumDistance: .zero)
.onChanged { value in
if let newValue = valueFromChartProxy(value.location.x, chartProxy) {
highlightedValue = newValue
}
}
return longPress.sequenced(before: drag)
.updating($dragState) { value, gestureState, _ in
switch value {
case .first(true):
// * This is never called
gestureState = .pressing
case .second(true, let drag):
// * Drag is often nil
// * When drag is nil, we lack access to the location
gestureState = .dragging(translation: drag?.translation ?? .zero)
default:
// * This is never called
gestureState = .inactive
}
onDragChange(gestureState)
}
}
}
struct DataPoint: Identifiable {
let id = UUID()
let category: String
let value: Double
}
struct ContentView: View {
let dataPoints = [
DataPoint(category: "A", value: 5),
DataPoint(category: "B", value: 3),
DataPoint(category: "C", value: 8),
DataPoint(category: "D", value: 2),
DataPoint(category: "E", value: 7)
]
@State private var highlightedCategory: String? = nil
@State private var dragState = DragState.inactive
var body: some View {
VStack {
Text("Bar Chart with Gesture Interaction")
.font(.headline)
.padding()
Chart {
ForEach(dataPoints) { dataPoint in
BarMark(
x: .value("Category", dataPoint.category),
y: .value("Value", dataPoint.value)
)
.foregroundStyle(highlightedCategory == dataPoint.category ? Color.red : Color.gray)
.annotation(position: .top) {
if highlightedCategory == dataPoint.category {
Text("\(dataPoint.value, specifier: "%.1f")")
.font(.caption)
.foregroundColor(.primary)
}
}
}
}
.frame(height: 300)
.chartOverlay { chartProxy in
ChartGestureOverlay<String>(
highlightedValue: $highlightedCategory,
chartProxy: chartProxy,
valueFromChartProxy: { xPosition, chartProxy in
if let category: String = chartProxy.value(atX: xPosition) {
return category
}
return nil
},
onDragChange: { newDragState in
dragState = newDragState
}
)
}
.onChange(of: highlightedCategory, { oldCategory, newCategory in
})
}
.padding()
}
}
#Preview {
ContentView()
}
Thank you!
I have an app for musicians that works with Songs and Setlists. The logical structure is as follows:
A Setlist contains Songs.
A Song has Sections, which include Lines (chords & lyrics).
I want to view my Setlist in a "Page View," similar to a book where I can swipe through pages. In this view, the Song Sections are wrapped into columns to save screen space. I use a ColumnsLayout to calculate and render the columns, and then a SplitToPages modifier to divide these columns into pages.
Problem: The TabView sometimes behaves unexpectedly when a song spans multiple pages during rendering. This results in a transition that is either not smooth or stops between songs.
Is there a better way to implement this behavior? Any advice would be greatly appreciated.
struct TestPageView: View {
struct SongWithSections: Identifiable {
var id = UUID()
var title: String
var section: [String]
}
var songSetlistSample: [SongWithSections] {
var songs: [SongWithSections] = []
//songs
for i in 0...3 {
var sections: [String] = []
for _ in 0...20 {
sections.append(randomSection() + "\n\n")
}
songs.append(SongWithSections(title: "Song \(i)", section: sections))
}
return songs
}
func randomSection() -> String {
var randomSection = ""
for _ in 0...15 {
randomSection.append(String((0..<Int.random(in: 3..<10)).map{ _ in "abcdefghijklmnopqrstuvwxyz".randomElement()! }) + " ")
}
return randomSection
}
var body: some View {
GeometryReader {geo in
TabView {
ForEach(songSetlistSample, id:\.id) {song in
let columnWidth = geo.size.width / 2
//song
ColumnsLayout(columns: 2, columnWidth: columnWidth, height: geo.size.height) {
Text(song.title)
.font(.largeTitle)
ForEach(song.section, id:\.self) {section in
Text(section)
}
}
.modifier(SplitToPages(pageWidth: geo.size.width, id: song.id))
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}
public struct ColumnsLayout: Layout {
var columns: Int
let columnWidth: CGFloat
let height: CGFloat
let spacing: CGFloat = 10
public static var layoutProperties: LayoutProperties {
var properties = LayoutProperties()
properties.stackOrientation = .vertical
return properties
}
struct Column {
var elements: [(index: Int, size: CGSize, yOffset: CGFloat)] = []
var xOffset: CGFloat = .zero
var height: CGFloat = .zero
}
public func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> CGSize {
let columns = arrangeColumns(proposal: proposal, subviews: subviews, cache: &cache)
guard let maxHeight = columns.map({ $0.height}).max() else {return CGSize.zero}
let width = Double(columns.count) * self.columnWidth
return CGSize(width: width, height: maxHeight)
}
public func placeSubviews(in bounds: CGRect,
proposal: ProposedViewSize,
subviews: Subviews,
cache: inout Cache) {
let columns = arrangeColumns(proposal: proposal, subviews: subviews, cache: &cache)
for column in columns {
for element in column.elements {
let x: CGFloat = column.xOffset
let y: CGFloat = element.yOffset
let point = CGPoint(x: x + bounds.minX, y: y + bounds.minY)
let proposal = ProposedViewSize(width: self.columnWidth, height: proposal.height ?? 100)
subviews[element.index].place(at: point, anchor: .topLeading, proposal: proposal)
}
}
}
private func arrangeColumns(proposal: ProposedViewSize, subviews: Subviews, cache: inout Cache) -> [Column] {
var currentColumn = Column()
var columns = [Column]()
var colNumber = 0
var currentY = 0.0
for index in subviews.indices {
let proposal = ProposedViewSize(width: self.columnWidth, height: proposal.height ?? 100)
let size = subviews[index].sizeThatFits(proposal)
let spacing = size.height > 0 ? spacing : 0
if currentY + size.height > height {
currentColumn.height = currentY
columns.append(currentColumn)
colNumber += 1
currentColumn = Column()
currentColumn.xOffset = Double(colNumber) * (self.columnWidth)
currentY = 0.0
}
currentColumn.elements.append((index, size, currentY))
currentY += size.height + spacing
}
currentColumn.height = currentY
columns.append(currentColumn)
return columns
}
}
struct SplitToPages: ViewModifier {
let pageWidth: CGFloat
let id: UUID
@State private var pages = 1
func body(content: Content) -> some View {
let contentWithGeometry = content
.background(
GeometryReader { geometryProxy in
Color.clear
.onChange(of: geometryProxy.size) {newSize in
guard newSize.width > 0, pageWidth > 0 else {return}
pages = Int(ceil(newSize.width / pageWidth))
}
.onAppear {
guard geometryProxy.size.width > 0, pageWidth > 0 else {return}
pages = Int(ceil(geometryProxy.size.width / pageWidth))
}
})
Group {
ForEach(0..<pages, id:\.self) {p in
ZStack(alignment: .topLeading) {
contentWithGeometry
.offset(x: -Double(p) * pageWidth, y: 0)
.frame(width: pageWidth, alignment: .leading)
VStack {
Spacer()
HStack {
Spacer()
Text("\(p + 1) of \(pages)")
.padding([.leading, .trailing])
}
}
}
.id(id.description + p.description)
}
}
}
}