Post

Replies

Boosts

Views

Activity

Dragging horizontally with DragGesture
I am trying to achieve a naturally feeling movement of an entity, but the drag gesture always gives me movement perpendicular the view. That means if I restrict y to the stay the same I can only move the model left and right. A movement (of the mouse) upwards would result exclusive into a movement up/down. My model has many sub entities and I found that I need to create a box as collision shape so that I can move the entire model. Previously if I generated collision shapes it would only move the individual part. This code is not working mostly, except the restriction for y which feels very much like a hack. Is there a facility by the system that would rotate the movement vector along the x axis such that y becomes zero? Or am I approaching this wrong? how would you move objects in immersive space usually? import SwiftUI import RealityKit import RealityKitContent struct ImmersiveView: View { @State private var initialDragOffset: SIMD3<Float> = .zero var body: some View { RealityView { content in async let model = Entity(named: "01-TFKmono2-Normal-PremiumGrey", in: realityKitContentBundle) if let model = try? await model { // Set the model's position to the world origin model.position = [0, 0, 0] // Offset the model in the y direction by half its height let boundingBox = model.visualBounds(relativeTo: nil) let boxSize = boundingBox.extents // Create the collision box and set it to the model let collision = CollisionComponent(shapes: [.generateBox(size: [boxSize.x, boxSize.y, boxSize.z]).offsetBy(translation: .init(x: 0, y: boxSize.y / 2, z: 0))], isStatic: false) model.components.set(collision) // Set the InputTargetComponent and add the model to the content model.components.set(InputTargetComponent()) content.add(model) // move the mode 2 meters in front of viewer model.position.z = -2 } } .gesture(DragGesture() .targetedToAnyEntity() .onChanged { value in if initialDragOffset == .zero { // Calculate the initial drag offset at the beginning of the drag let startLocation = value.convert(value.startLocation3D, from: .local, to: value.entity.parent!) initialDragOffset = value.entity.position - SIMD3<Float>(startLocation.x, startLocation.y, startLocation.z) } // Convert the 3D location of the drag gesture to the entity's parent coordinate space let dragLocation = value.convert(value.location3D, from: .local, to: value.entity.parent!) var newPosition = SIMD3<Float>(dragLocation.x, dragLocation.y, dragLocation.z) + initialDragOffset // don't modify y coordinate so that model remains standing on ground newPosition.y = value.entity.position.y // Set the entity's position to the new position value.entity.position = newPosition }.onEnded({ value in initialDragOffset = .zero })) } } #Preview { ImmersiveView() .previewLayout(.sizeThatFits) }
3
1
1.6k
Aug ’23
VisionOS app UX/UI for showing hiding the main window
Do you always have to have a main window? Or is there a way to only have a mixed experience? how would you go about selecting a model from a list and once you select it, I want to hide the list and instead show the model in front of you in an immersive view. Is there a way to re-show the list? I know that there's the X button at the bottom of the main window, but once you close that, how do you get back to it?
2
0
1.8k
Aug ’23
SwiftCharts: How to clip data to specific range?
I found that can customise the range of the x and y axes. But my problem is that for line marks some data might just be outside the axes range. If I add .clipped to the chart that would limit it, but then it also clips off some of the axis marks. No Clipping: With Clipping: you see the green line go over the AxisValueLabel area and the topmost label is clipped off. One way I can imagine addressing this without enabling clipping is to create an interpolated value for values that are just outside the chart range so that the line ends exactly at the min/max.
5
2
2.4k
Jun ’22
SwiftCharts: how to manage colors and groupings
I want to draw a chart where I have two line marks (one for each child each) and behind it area marks for percentiles. If I don't add any foregroundStyle then the line marks get connected. struct GrowthChart: View { @ChartContentBuilder func oneSlice(row: PercentileRow, slice: Slice) -> some ChartContent { AreaMark( x: .value("Day", row.month), yStart: .value("Max", row.dictionary[slice.startKey]!), yEnd: .value("Min", row.dictionary[slice.endKey]!) ) .foregroundStyle(by: .value("Percentile", slice.number)) } let percentileColors: [Color] = [ .blue.opacity(0.1),   .blue.opacity(0.2),   .blue.opacity(0.3),   .blue.opacity(0.4),   .blue.opacity(0.5),   .blue.opacity(0.4),   .blue.opacity(0.3),   .blue.opacity(0.2),   .blue.opacity(0.1)   ] var body: some View { VStack { Chart { ForEach(percentiles.rows) { row in ForEach(slices) { slice in oneSlice(row: row, slice: slice) } } ForEach(children) { child in ForEach(child.data) { dataPoint in LineMark( x: .value("Month", dataPoint.month), y: .value("Height", dataPoint.height) ) .foregroundStyle(by: .value("Name", child.name)) } } } .chartForegroundStyleScale( range: Gradient (colors: percentileColors) ) .aspectRatio(contentMode: .fit) .padding() Spacer() }.padding() } } I don't understand how to group the individual marks. Apparently you have to add a foregroundStyle to each with a .by specifying a category. I found this chartForegroundStyleScale in an example on the internet, but I can only get it to show this gradient. But how do I specify different colors for the LineMarks?
1
0
2k
Jun ’22
SwiftUI: Laziness of List Interferes with Selection and Presentation of Detail
iOS 14 introduces some laziness in certain views, like for example there are now lazy variants of HStack and VStack. I’ve been working on a SwiftUI-version of an app of mine and the findings of my research for these bugs led me to believe that Apple added some lazy optimisations to Lists as well.  Unfortunately those optimisations seem to be breaking selection and presentation of detail views to a degree that they would be show stoppers for any universal app relying on List and its automatic promotion to being a split view on iPad. I filed this as FB8521674 in the Apple Feedback App. I am posting the full report here as well as these findings might be helpful to other developers who were as stuck as I am, hoping that Apple will fix this issue . Bug Report On iPad, List is supposed to present the destination of NavigationLinks when the link’s tag matches the selection binding’s value. But that only occurs if the referenced row is presently visible. Setting selection programmatically only presents the detail view if the referenced row is presently visible. That goes both for setting the selected binding to a value before the list appears as well as setting it while it is visible. The selection highlight is not being updated by programmatic selection. Also, if you hide the list on iPad via the button on the top left and show it again, the selection highlight also disappears. Steps to Reproduce Open the attached sample project Run it in iPad simulator in Landscape orientation Notice that it shows “Africa/Asmara Detail” on the right side, but there is no selection highlight on the list on the left If you click any row, then selection highlight is updated, as is the detail view While at the top of the list, press the arrow button above the list Notice that nothing changes Now scroll down the list. As soon as the row for “America/Adak” appears, the detail view is being updated, but the selection highlight is still missing Rotate to Portrait orientation (which hides the List as soon as a selection is being made) Scroll to the top of the list Tap the arrow button again, nothing happens Scroll down until “America/Adak” becomes visible, now the detail view gets updated (selection highlight does not show) and the list disappears What I expected to happen when the app shows in landscape (#3) the “Africa/Asmera” row should be highlighted when you tap the arrow (#5) the “America/Adak” row should be highlighted (and scrolled to) and the related detail view be presented when in Portrait, the sudden dismissal of the list is confusing. I would prefer to have the auto-hiding only occur if the user makes a change of the selection. But if you must hide it, then at least the selection highlight should be visible hiding and re-showing the list on iPad Landscape should preserve the selection highlight What actually happened programmatic change of the selection never updates the highlight a detail page is only presented as soon as the referenced row becomes visible if you are scrolling, on iPad Portrait, and a selected item becomes visible the list is suddenly dismissed hiding and re-showing the list (iPad Landscape) doesn’t preserve selection highlight Sample Project The sample project is so short that I can reproduce it here for you: import SwiftUI @main struct SelectionBugApp: App { // the navigation presentation is only done on the // initially visible rows // selection is never updated @State var selectedID: String? = "Africa/Asmara" &#9;var body: some Scene { &#9;&#9;WindowGroup { &#9;&#9;&#9;NavigationView { &#9;&#9;&#9;&#9;List(selection: $selectedID) { &#9;&#9;&#9;&#9;&#9;ForEach(TimeZone.knownTimeZoneIdentifiers, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;id: \.self) { identifier in &#9;&#9;&#9;&#9;&#9;&#9;NavigationLink(identifier,  &#9;&#9;&#9;&#9;&#9;&#9; destination: Text("\(identifier) Detail"),  &#9;&#9;&#9;&#9;&#9;&#9; tag: identifier,  &#9;&#9;&#9;&#9;&#9;&#9; selection: $selectedID) &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;.navigationTitle("Time Zones") &#9;&#9;&#9;&#9;&#9;.navigationBarItems(trailing: &#9;&#9;&#9;&#9;&#9;&#9; Button(action: { &#9;&#9;&#9;&#9;&#9;&#9;&#9; // this presents the navigation destination, &#9;&#9;&#9;&#9;&#9;&#9;&#9; // but only if the row has been visible &#9;&#9;&#9;&#9;&#9;&#9;&#9; // selection is never updated &#9;&#9;&#9;&#9;&#9;&#9;&#9; self.selectedID = "America/Adak" &#9;&#9;&#9;&#9;&#9;&#9; }, label: { &#9;&#9;&#9;&#9;&#9;&#9;&#9; Image(systemName: "location.fill") &#9;&#9;&#9;&#9;&#9;&#9; }) &#9;&#9;&#9;&#9;&#9;) &#9;&#9;&#9;&#9; }    &#9; }  &#9;} } Just post it into a new iOS SwiftUI app and you can follow along.
5
1
2.1k
Aug ’20
How do I scroll a List to a specific item?
I have the following code working to scroll to a given item. But the combination of ScrollView + LazyStackview doesn't give me proper selection highlighting, like a List would. So my questions are: is there a way to scroll a List to a specific item, i.e. can I use ScrollViewReader with Lists? is there a way to emulate the row highlighting which you press on the cell? And to abort selection in the default way by scrolling a bit? struct ContentView: View { let timezones = TimeZone.knownTimeZoneIdentifiers.map { TimeZone(identifier: $0)! } var body: some View { let continents = Set(timezones.compactMap { $0.continent }).sorted() ScrollView { ScrollViewReader { value in LazyVStack(alignment: .leading, spacing: 5, pinnedViews: [.sectionHeaders]) { ForEach(continents, id: \.self) { continent in let continentTZ = timezones.filter { $0.continent == continent} Section(header: HeaderView(title: continent)) { ForEach(continentTZ) { timezone in Button(action: { // this will dismiss the selection }) { VStack { TimeZoneCell(timezone: timezone) Divider() } } } } } }.onAppear() { value.scrollTo(TimeZone.current.identifier, anchor: .center) } } }.navigationBarTitle(Text("Time Zones"), displayMode: .inline) } }
3
0
1.8k
Jul ’20
Rubiks Cube
Wow, this prowess on the cube at the start. Had me skip back to the start a couple of times. I must ask ... is that a cut right at the end hiding a few more moves? Or was Lui done exactly when finishing his introductory remarks? cheers Oliver
0
0
620
Jul ’20
Chapter 4
I had some issues with the code, so I ended up creating an initializer instead of relying on automatic-synthesis. Also, I don't quite understand why all functions needed to be public... possibly because only public functions can be called from other pages? {     public let instrument: Instrument.Kind     public let length: Int     public let notes: [MIDINotes]     public init(instrument: Instrument.Kind, length: Int, notes: [MIDINotes])     {         self.instrument = instrument         self.length = length         self.notes = notes     }     public func note(for frame: Int) -> MIDINotes {         guard frame < notes.count else {             return .rest         }         return notes[frame]     } } Here's my solution for the performance: func performance(owner: Assessable) {     let numberOfBeats = 32   // two bars of 4/4     let duration = 16.0      // seconds     var bass = Track(instrument: .bassGuitar, length: numberOfBeats, notes: bassNotes)     var piano = Track(instrument: .piano, length: numberOfBeats, notes: trebleNotes)     let tracks = [bass, piano]     let interval = duration / Double(numberOfBeats)     var index = 0     Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { (timer) in         guard index < numberOfBeats else         {             owner.endPerformance()             timer.invalidate()             return         }                  for track in tracks {             playInstrument(track.instrument, note: track.note(for: index))         }         index += 1     } }
0
0
602
Jul ’20
Change Material base color
Hi,I have a USDZ model loaded and as far as I can tell I am using RealityKit to display it. Is there a way to change the properties of certain material so that the already-displaying model gets a different color in parts where this material is used?i.e. I have a model of a baby stroller and I want to switch between a couple of different colors for the sun roof.I couldn't find any documentation or sample to that effect.Any help would be much appreciatedOliver
1
0
1.9k
Apr ’20