Provide 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

Page-Curl Shader -- Pixel transparency check is wrong?
Given I do not understand much at all about how to write shaders I do not understand the math associated with page-curl effects I am trying to: implement a page-curl shader for use on SwiftUI views. I've lifted a shader from HIROKI IKEUCHI that I believe they lifted from a non-metal shader resource online, and I'm trying to digest it. One thing I want to do is to paint the "underside" of the view with a given color and maintain the transparency of rounded corners when they are flipped over. So, if an underside pixel is "clear" then I want to sample the pixel at that position on the original layer instead of the "curl effect" pixel. There are two comments in the shader below where I check the alpha, and underside flags, and paint the color red as a debug test. The shader gives this result: The outside of those rounded corners is appropriately red and the white border pixels are detected as "not-clear". But the "inner" portion of the border is... mistakingly red? I don't get it. Any help would be appreciated. I feel tapped out and I don't have any IRL resources I can ask. // // PageCurl.metal // ShaderDemo3 // // Created by HIROKI IKEUCHI on 2023/10/17. // #include <metal_stdlib> #include <SwiftUI/SwiftUI_Metal.h> using namespace metal; #define pi float(3.14159265359) #define blue half4(0.0, 0.0, 1.0, 1.0) #define red half4(1.0, 0.0, 0.0, 1.0) #define radius float(0.4) // そのピクセルの色を返す [[ stitchable ]] half4 pageCurl ( float2 _position, SwiftUI::Layer layer, float4 bounds, float2 _clickedPoint, float2 _mouseCursor ) { half4 undersideColor = half4(0.5, 0.5, 1.0, 1.0); float2 originalPosition = _position; // y座標の補正 float2 position = float2(_position.x, bounds.w - _position.y); float2 clickedPoint = float2(_clickedPoint.x, bounds.w - _clickedPoint.y); float2 mouseCursor = float2(_mouseCursor.x, bounds.w - _mouseCursor.y); float aspect = bounds.z / bounds.w; float2 uv = position * float2(aspect, 1.) / bounds.zw; float2 mouse = mouseCursor.xy * float2(aspect, 1.) / bounds.zw; float2 mouseDir = normalize(abs(clickedPoint.xy) - mouseCursor.xy); float2 origin = clamp(mouse - mouseDir * mouse.x / mouseDir.x, 0., 1.); float mouseDist = clamp(length(mouse - origin) + (aspect - (abs(clickedPoint.x) / bounds.z) * aspect) / mouseDir.x, 0., aspect / mouseDir.x); if (mouseDir.x < 0.) { mouseDist = distance(mouse, origin); } float proj = dot(uv - origin, mouseDir); float dist = proj - mouseDist; float2 linePoint = uv - dist * mouseDir; half4 pixel = layer.sample(position); if (dist > radius) { pixel = half4(0.0, 0.0, 0.0, 0.0); // background behind curling layer (note: 0.0 opacity) pixel.rgb *= pow(clamp(dist - radius, 0., 1.) * 1.5, .2); } else if (dist >= 0.0) { // THIS PORTION HANDLES THE CURL SHADED PORTION OF THE RESULT // map to cylinder point float theta = asin(dist / radius); float2 p2 = linePoint + mouseDir * (pi - theta) * radius; float2 p1 = linePoint + mouseDir * theta * radius; bool underside = (p2.x <= aspect && p2.y <= 1. && p2.x > 0. && p2.y > 0.); uv = underside ? p2 : p1; uv = float2(uv.x, 1.0 - uv.y); // invert y pixel = layer.sample(uv * float2(1. / aspect, 1.) * float2(bounds[2], bounds[3])); // ME<---- if (underside && pixel.a == 0.0) { //<---- PIXEL.A IS 0.0 WHYYYYY pixel = red; } // Commented out while debugging alpha issues // if (underside && pixel.a == 0.0) { // pixel = layer.sample(originalPosition); // } else if (underside) { // pixel = undersideColor; // underside // } // Shadow the pixel being returned pixel.rgb *= pow(clamp((radius - dist) / radius, 0., 1.), .2); } else { // THIS PORTION HANDLES THE NON-CURL-SHADED PORTION OF THE SAMPLING. float2 p = linePoint + mouseDir * (abs(dist) + pi * radius); bool underside = (p.x <= aspect && p.y <= 1. && p.x > 0. && p.y > 0.); uv = underside ? p : uv; uv = float2(uv.x, 1.0 - uv.y); // invert y pixel = layer.sample(uv * float2(1. / aspect, 1.) * float2(bounds[2], bounds[3])); // ME if (underside && pixel.a == 0.0) { //<---- PIXEL.A IS 0.0 WHYYYYY pixel = red; } // Commented out while debugging alpha issues // if (underside && pixel.a == 0.0) { // // If the new underside pixel is clear, we should sample the original image's pixel. // pixel = layer.sample(originalPosition); // } else if (underside) { // pixel = undersideColor; // } } return pixel; }
1
0
281
Oct ’24
SwiftUI > missed . on frame modifier
Recently I've made 1 character mistake in my code and have hard time during searching what was the problem. Basically I forgot to set dot near one of the frame modifiers and compiler did not warn me, but during app running I got 100% CPU and rocket increase of RAM (on real app). Feels like recursion, but no any hint in call stack inside Xcode on crash stop. struct BadView: View { var body: some View { Color.red frame(height: 36) } } I would like to see at least warning for such cases. Problem may look simple on this small example, but if you added 1k+ lines after last compilation - searching this type of errors could be problematic when you have no idea what to search.
1
0
121
Oct ’24
How do I add alternative app icons for a SwiftUI tvOS app?
I am familiar with providing the main layered app icon for a tvOS project, but I cannot work out how to successfully add support for alternative layered icons in the info.plist and/or asset catalog and/or build settings for a SwiftUI (or Swift) tvOS project. Whenever I check the result of UIApplication.shared.supportsAlternateIcons it returns false I have witnessed other tvOS apps such as Plex successfully switch the app icon, so it must be possible to do. How should the project be configured, what am I missing?
0
0
207
Oct ’24
NavigationSplitView does not properly show detail pages on macOS 15
The Problem My team has recently discovered a problem in one of our macOS apps. It uses SwiftUI and Combine, as it still needs to support macOS 13. It uses a NavigationSplitView to display a sidebar-detail UI. On macOS 15, we started running into a bug: When selecting an item from the sidebar, the corresponding detail does not initially show up, and a detail page shows up only when selecting a second item from the sidebar. The following message would be printed into Xcode's console: Publishing changes from within view updates is not allowed, this will cause undefined behavior. This message would only get printed into the console, and would not be attached to any specific line. Oftentimes, selecting a subsequent item from the sidebar also either completely clears the detail page, doesn't do anything, and there was a crash reported as well. The app is compiled using Xcode 16.0. Architecture Overview The app uses NavigationSplitView with multiple different detail pages. .id is attached to the detail view in its corresponding NavigationLink, which used to properly show the corresponding detail page. The ID is stored in an observable AppState, which uses Combine's ObservableObject in the production app, and Observation's Observable in the minimal example. Example Code Minimal Reproductible Example You can see a minimal reproducible example here: https://github.com/buresdv/Navigation-Problems This example also features a debug field at the end of the sidebar, called "navigationSelection". When clicking one of the items, the ID gets correctly set, but the detail page does not update. Production App The production app is a bit more complex, but the core system is the same. For complete code, see: https://github.com/buresdv/Cork Some relevant lines include the navigation root, sidebar list, and the navigation links Notes We were able to reproduce these issues on multiple user systems This issue seems to have started occuring when we updated to macOS 15 At the same time, we updated the app to Strict Concurrency Checking and Swift 6, although we did not change anything in the navigation system
3
0
402
Oct ’24
[iPadOS 18] A series of TabBar questions
Hello, I am currently implementing the new iPadOS 18 TabBar with the new Tab API, but there are several things that don't look very good or aren't operating quite the way I'd hope and would like to know if there is a way around them or to change them. Here is what my sidebar for the TabBar looks like: My questions: The tabViewSidebarBottomBar isn't actually at the "bottom". Instead there is a gap below which you can see the sidebar scrolling. Is there a way to get the tabViewSidebarBottomBar actually at the bottom? Is there a way to make it so that the sections themselves are also reorderable? Can we turn scrollIndicators to .never or are we stuck with them being on? Is there any way at all to make the SF Symbols in the sidebar render in another color mode, particularly .palette? Is it possible to allow sections in between plain tabs? Like I want Dashboard, then the whole Events section, then the rest can continue. On iPhone why are sections not honored at all, in any way? Like even if they weren't going to be expandable menus, at least treating it like a list section would allow some visual hierarchy?! Bonus Question: Any way to make the tabViewSidebarHeader sticky so it's always at the top? Thank you in advance!
1
0
330
Oct ’24
Can I fix this big difference between swiftui preview and actual watch widget layout?
Hi, working on customising my live activity Smart Stack layout for ios18. A thing that is very frustrating is that I consistently looks different for me in the Xcode preview and on the actual watch. See attached screenshots below. The sizes are different, and italic doesn't work on the watch, for example. It makes it time-consuming and unpredictable, so I was wondering if this is a known issue or if I'm doing something wrong, and also can I do anything? thanks edit: this is the layout: var body: some View { VStack(alignment: .center, spacing:4) { HStack(alignment: .center) { IconView(resource: "n-compact-w", bgColor: Color.checkedIn, padding: 2, paddingRight: 6, paddingBottom: 6) .frame(maxWidth: 25, maxHeight: 25).aspectRatio(1, contentMode: .fit) Text("Checked Out") .font(.title3).bold() } Text(status.loc) .font(.headline) .multilineTextAlignment(.center) Text(FormatUtils.getFormattedDateTime(status.time)).font(.subheadline) .multilineTextAlignment(.center).italic() } }
4
0
270
Oct ’24
Elevated TabBar in iPadOS 18 covers Navigation-/Toolbar
The new "elevated" tab bar in iPadOS 18 covers the Navigation-/Toolbar of views within. A very simple example: import SwiftUI @main struct SampleApp: App { @State var selection: Int? var body: some Scene { WindowGroup { TabView { NavigationSplitView { List(0..<10, selection: $selection) { item in Text("Item \(item)") .tag(item) } } detail: { if let selection { Text("Detail for \(selection)") .navigationTitle("Item \(selection)") .navigationBarTitleDisplayMode(.inline) } else { Text("No selection") } }.tabItem { Label("Items", systemImage: "list.bullet") } Text("Tab 2") .tabItem { Label("Tab 2", systemImage: "list.bullet") } Text("Tab 3") .tabItem { Label("Another Tab", systemImage: "list.bullet") } } } } } I've tried using .safeAreaInset/.safeAreaPadding for the detail views, but they don't affect the NavigationBar, only the content within. Is there a way to move the NavigationBar down, so its items stay visible?
1
0
218
Oct ’24
$FocusState and Lists with rows containing TextFields
While I've seen examples of using $FocusState with Lists containing "raw" TextFields, in my use case, the List rows are more complex than that and contain multiiple elements, including TextFields. I obviously don't understand something fundamental here, because I am completely unable to get TextField-to-TextField tabbing to work. Can someone set me straight? Sample code demonstrating the issues: // // ContentView.swift // ListElementFocus // // Created by Richard Aurbach on 10/12/24. // import SwiftUI /// NOTE: in my actual app, the data model is actually a set of SwiftData /// PresistentModel objects. Here, I'm simulating them with an Observable. @Observable final class TestModel: Identifiable { public var id: UUID public var checked: Bool = false public var title: String = "Test" public var subtitle: String = "Subtitle" init(checked: Bool = false, title: String, subtitle: String) { self.id = UUID() self.checked = checked self.title = title self.subtitle = subtitle } } struct ContentView: View { /// Instead of a @Query... @State var records: [TestModel] = [ TestModel(title: "First title", subtitle: "blah, blah, blah"), TestModel(title: "Second title", subtitle: "more nonsense"), TestModel(title: "Third title", subtitle: "even more nonsense"), ] @FocusState var focus: UUID? var body: some View { Form { Section { HStack(alignment: .top) { Text("Goal:").font(.headline) Text( "If a user taps in the TextField in any row, they should be able to tab from row to row using any keyboard which supports a tab key." ) } HStack(alignment: .top) { Text("#1:").font(.headline) Text( "While I will admit that this code is probaby total garbage, I haven't been able to find any way to make tabbing from row to row to work at all." ) } HStack(alignment: .top) { Text("#2:").font(.headline) Text( "Tapping the checkbox button causes the row to flash with the current accent color, and I can't find any way to turn that off." ) } } header: { Text("Problems").font(.title3).bold() }.headerProminence(.increased) Section { List(records) { record in ListRow(record: record, focus: focus) .onKeyPress(.tab) { focus = next(record) return .handled } } } header: { Text("Example: Selector of Editable Items").font(.title3).bold() }.headerProminence(.increased) } .padding() } private func next(_ record: TestModel) -> UUID { guard !records.isEmpty else { return UUID() } if record.id == records.last!.id { return records.first!.id } if let index = records.firstIndex(where: { $0.id == record.id }) { return records[index + 1].id } return UUID() } } struct ListRow: View { @Bindable var record: TestModel var focus: UUID? @FocusState var focusState: Bool init(record: TestModel, focus: UUID?) { self.record = record self.focus = focus self.focusState = focus == record.id } var body: some View { HStack(alignment: .top) { Button { record.checked.toggle() } label: { record.checked ? Image(systemName: "checkmark.square.fill") : Image(systemName: "square") }.font(.title2).focusable(false) VStack(alignment: .leading) { TextField("title", text: $record.title).font(.headline) .focused($focusState) Text("subtitle").italic() } } } } #Preview { ContentView() }
0
0
164
Oct ’24
Do update to @Observable properties have to be done on the main thread?
According to this old thread the answer is no. But I never understood why. In the old world. It was always required that you make changes to @Published properties on the main thread. In fact compiler would complain. In the main world, can you just update that in the background thread? And then SwiftUI take cares of refreshing the views on the main thread? So I guess that begs that question, why did it used to require it for @Published? Furthermore, I have recently gotten new crashes when update is done from background but I can't be sure it's related: For example I have the following, and the crash is as follows: @Observable class PlanViewModel { var stagingPlan: Plan? func savePlan() async { //some code here.... stagingPlan = nil //crash } } Is this issue potentially related to main thread? Should I do that assignment forcefully on main thread? call stack 1 call stack 2 call stack 3 I dont know how to troubleshoot this further as xcode doesnt provide me any info other than that one red line
1
0
217
Oct ’24
Availablility check is incorrect on visionOS
With this sample code here: import SwiftUI struct ContentView: View { var body: some View { Text("Hello world") .hoverEffect(isEnabled: true) } } private extension View { func hoverEffect(isEnabled: Bool) -> some View { if #available(iOS 17.0, *) { // VisionOS 2.0 goes in here? return self .hoverEffect(.automatic, isEnabled: isEnabled) } else { return self } } } You would expect if the destination was visionOS it would go into the else block but it doesn't. That seems incorrect since the condition should be true if the platform is iOS 17.0+. Also, I had this similar code that was distriubted via a xcframework and when that view is used in an app that is using the xcframework while running against visionOS there would be a runtime crash (EXC_BAD_ACCESS). The crash could only be reproduced when using that view from the xcframework and not the local source code. The problem was fixed by adding visionOS 1.0 to that availability check. But this shouldn't have been a crash in the first place. Does anyone have thoughts on this or possibly an explanation? Thank you!
5
2
329
Oct ’24
Badge signature has changed in iOS 18
Hi, I'm trying to add a badge to a Tab when a certain condition is met. Prior to iOS 18 I could do .badge(showBadge ? "Show" : nil). However, in iOS 18 I'm getting the following error message 'nil' cannot be used in context expecting type 'LocalizedStringKey'. Right clicking the .badge -> Jump to Definition shows the following /// Generates a badge for the tab from a localized string key. /// /// Use a badge to convey optional, supplementary information about a /// view. Keep the contents of the badge as short as possible. The string /// provided will appear as an indicator on the given tab. /// /// This modifier creates a ``Text`` view on your behalf, and treats the /// localized key similar to ``Text/init(_:tableName:bundle:comment:)``. For /// more information about localizing strings, see ``Text``. The /// following example shows a tab that has a "New Alerts" badge /// when there are new alerts. /// /// var body: some View { /// TabView { /// Tab("Home", systemImage: "house") { /// HomeView() /// } /// Tab("Alerts", systemImage: "bell") { /// AlertsView() /// } /// .badge(alertsManager.hasAlerts ? "New Alerts" : nil) /// } /// } /// /// - Parameter key: A string key to display as a badge. nonisolated public func badge(_ key: LocalizedStringKey) -> some TabContent<Self.TabValue> Here it looks like that the signature of .badge has changed to a non-nil LocalizedStringKey from pre-iOS 18 LocalizedStringKey?. Any ideas how to solve this?
2
0
183
Oct ’24
Skysphere flickering w attachment at finial display of scene
There is a flickering and slight dimming occurring specifically on skysphere, at initial load of the scene, when using Attachment. This is observed in the simulator and on the real device. Since we cannot upload a video illustrating the undesirable behaviour, I have to describe how to setup the project for you to observe it. To replicate the issue, follow these steps: Create a new visionOS app using Xcode template, see image. Configure the project to launch directly into an immersive space (set Preferred Default Scene Session Role to Immersive Space Application Session Role in Info.plist), see image. Replace all swift files with those you will find in the attached texts. Add the skysphere image asset Skydome_8k found at this Apple Sample App Presenting an artist’s scene. Launch the app in debug mode via Xcode and onto the AVP device or simulator Continuously open and dismiss the skysphere by pressing on buttons Open Skysphere and Close. Observe the skysphere flicker and dim upon display of the skysphere. The current workaround is commented in file ThreeSixtySkysphereRealityView at lines 65, 70, 71, and 72. Uncomment these lines, and the flickering and dimming do not occur. Are we using attachments wrongly? Is this behavior known and documented? Or, is there really a bug in visionOS? AppModel InitialImmersiveView MainImmersiveView TestSkysphereAttachmentFlickerApp ThreeSixtySkysphereRealityView
1
0
218
Oct ’24
Potential memory leaks in CLLocationUpdate.Updates
This is my first post here. Please guide me, if I need to provide more information to answer this post. I write a simple application, that monitors GPS position (location). I followed Apple documentation for LiveUpdates: https://developer.apple.com/documentation/corelocation/supporting-live-updates-in-swiftui-and-mac-catalyst-apps My app can monitor location in foreground, background or it can completely stop monitoring location. Background location, if needed, is switched on when application changes scenePhase to .background. But it is in the foreground, that memory leaks occur (according to Instruments/Leaks. Namely Leaks points to the instruction: let updates = CLLocationUpdate.liveUpdates() every time I start location and then stop it, by setting updatesStarted to false. Leaks claims there are 5x leaks there: Malloc 32 Bytes 1 0x6000002c1d00 32 Bytes libswiftDispatch.dylib OS_dispatch_queue.init(label:qos:attributes:autoreleaseFrequency:target:) CLDispatchSilo 1 0x60000269e700 96 Bytes CoreLocation 0x184525c64 Malloc 48 Bytes 1 0x600000c8f2d0 48 Bytes Foundation +[NSString stringWithUTF8String:] NSMutableSet 1 0x6000002c4240 32 Bytes LocationSupport 0x18baa65d4 dispatch_queue_t (serial) 1 0x600002c69c80 128 Bytes libswiftDispatch.dylib OS_dispatch_queue.init(label:qos:attributes:autoreleaseFrequency:target:) I tried [weak self] in Task, but it doesn't solve the leaks problem and causes other issues, so I dropped it. Anyway, Apple doesn't use it either. Just in case this is my function, which has been slightly changed comparing to Apple example, to suit my needs: func startLocationUpdates() { Task() { do { self.updatesStarted = true let updates = CLLocationUpdate.liveUpdates() for try await update in updates { // End location updates by breaking out of the loop. if !self.updatesStarted { self.location = nil self.mapLocation = nil self.track.removeAll() break } if let loc = update.location { let locationCoordinate = loc.coordinate let location2D = CLLocationCoordinate2D(latitude: locationCoordinate.latitude, longitude: locationCoordinate.longitude) self.location = location2D if self.isAnchor { if #available(iOS 18.0, *) { if !update.stationary { self.track.append(location2D) } } else { // Fallback on earlier versions if !update.isStationary { self.track.append(location2D) } } } } } } catch { // } return } } Can anyone help me locating these leaks?
3
0
261
Oct ’24
SwiftUI Scroll Issue with Keyboard Type Change
Hello, I'm developing with SwiftUI and have encountered some bug-like behavior that I haven't been able to resolve, so I'm seeking your assistance. I'm building my view using TextEditor, ScrollViewReader, and List, and I've noticed a strange behavior. When the TextEditor at the bottom of the view is focused and the keyboard is displayed, if I change the keyboard type to Emoji and then switch back to the language keyboard, the scroll becomes misaligned. Although the TextEditor remains focused, when this bug occurs, the view's offset is reset as if the focus was lost. Could you help me with this?
0
1
168
Oct ’24
Using Generic SwiftData Modules
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) } } } }
3
0
234
2w