Hi,
Suppose I want to create an School management App that have little complex views so I need a three versions of each view one for Mac and one for iPadOS and one for iOS, cause using platform detector on same view and adjusting layout will make things messy. So what's the best way to achieve that ? Separate project to each platform ? maybe Targets which I still don't understand cause modifying a view in any target will be reflected to other targets so what's the best practice here ? Im working with SwiftUI
Kind Regards
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
Hi! I'm trying to do a forEach loop on an array of objects. Here's my code :
ForEach($individus) { $individu in
if individu.reussite == true {
individu.score -= 10
} else {
individu.score = (individu.levees * 10) + 20 + individu.score
}
}
I have an error on the code in the 'if' saying that "Type '()' cannot conform to 'View'", but I have no idea on how solving this problem.
When a large number of NavigationLinks is within a LazyVStack (or LazyVGrid), ressource usage gets higher (and stays high) the further a user scrolls down.
A simple example to reproduce this:
NavigationStack {
ScrollView {
LazyVStack {
ForEach(0..<5000) { number in
NavigationLink(value: number) {
Text("Number \(number)")
}
}
}
}
.navigationDestination(for: Int.self) { number in
Text("Details for number \(number)")
}
}
List does not exhibit this behavior but is not suitable for my use case.
I am working on a SwiftUI TabView with the .page style (indexDisplayMode: .never). I want to track the minX property of each tab's view using GeometryReader. However, I noticed inconsistent behavior when scrolling between pages.
Here's the simplified code:
import SwiftUI
struct ContactScreenView: View {
let text: String
var body: some View {
ZStack {
Color.red.opacity(0.4).ignoresSafeArea()
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text(text)
}
.padding()
}
}
}
struct DemoView: View {
@State private var selectedTab: Int = 0
var body: some View {
VStack {
TabView(selection: $selectedTab) {
ContactScreenView(text: "followers")
.background(
GeometryReader(content: { geometry -> Color in
let minX = geometry.frame(in: .global).minX
print(minX)
return Color.clear
})
)
.tag(0)
ContactScreenView(text: "following")
.tag(1)
ContactScreenView(text: "blocked")
.tag(2)
ContactScreenView(text: "Shared")
.tag(3)
}
.tabViewStyle(.page(indexDisplayMode: .never))
}
}
}
#Preview {
DemoView()
}
Observed Behavior:
When I scroll to the second page (index 1), the minX value updates correctly to screenWidth * 1, as expected.
When I scroll to the third page (index 2), the minX value doesn't update at all.
The ideal behavior would be for minX to update to screenWidth * 2 for the third page and so on, for subsequent pages.
Expected Behavior:
The minX value should correctly reflect the global position of each page as I scroll through the TabView. For example:
Page 0: minX = 0
Page 1: minX = screenWidth * 1
Page 2: minX = screenWidth * 2
And so on.
I understand this is a known issue, but it’s truly unacceptable that it remains unresolved. Allowing users to customize toolbars is a fundamental macOS feature, and it has been broken since the release of macOS 15.
How is it possible that this issue persists even in macOS 15.3 beta (24D5040f)?
FB15513599
import SwiftUI
struct ContentView: View {
@State private var showEditItem = false
var body: some View {
VStack {
VStack {
Text("Instructions to reproduce the crash")
.font(.title)
.padding()
Text("""
1. Click on "Toggle Item"
2. In the menu go to File > New Window
3. In new window, click on "Toggle Item"
""")
}
.padding()
Button {
showEditItem.toggle()
} label: {
Text("Toggle Item")
}
}
.padding()
.toolbar(id: "main") {
ToolbarItem(id: "new") {
Button {
} label: {
Text("New…")
}
}
if showEditItem {
ToolbarItem(id: "edit") {
Button {
} label: {
Text("Edit…")
}
}
}
}
}
}
I'm pretty new to Swift and SwiftUI. I'm making my first app for sorting a gallery with some extra features.
I was using my own iPhone for testing and just started testing my app on other Apple products.
Everything works fine on iPad Air M1, iPhone 15 Pro, iPhone 15 Pro Max, iPhone 13, iPhone XS (Simulator), and iPhone 11 Pro (Simulator). However, when I tried to show my app to a family member with an iPhone 11, I came across an issue.
Issue Description:
My app takes all photos from iPhone's native gallery, then you can sort it by some spesific filters and delete pictures. It just looks like the native gallery. (I can add photos later if needed) You can just scroll the gallery by swiping up and down. You can press the select button and start selecting pictures to delete.
I recently added a drag-to-select-multiple-pictures feature. This makes it feel more like the native iOS experience, eliminating the need to tap each picture individually.
However, on the iPhone 11, the moment you open the app, you can't scroll. Scrolling is completely locked. You can still select pictures by tapping or dragging, so it's not a touch area issue. The same issue persists on the iPhone 11 simulator.
And I think I found the problematic part in my (sadly messy) ContentView.swift file;
ScrollView {
RefreshControl(coordinateSpace: .named("refresh")) {
await viewModel.refreshMediaItems()
}
LazyVGrid(columns: gridColumns, spacing: UIDevice.current.userInterfaceIdiom == .pad ? 12 : 4) {
let items = viewModel.filteredItems(typeFilter: mediaTypeFilter, specialFilter: specialFilter)
ForEach(Array(zip(items.indices, items)), id: \.1.id) { index, item in
MediaThumbnailView(
item: item,
isSelected: selectedItems.contains(item.id),
viewModel: viewModel,
onLongPress: {
if !isSelectionMode {
toggleSelectionMode()
selectedItems.insert(item.id)
}
},
onTap: {
if isSelectionMode {
toggleSelection(item: item)
} else {
viewModel.selectItem(item)
}
}
)
.aspectRatio(1, contentMode: .fit)
.background(
GeometryReader { geometry in
let frame = geometry.frame(in: .named("grid"))
Color.clear.preference(
key: ItemBoundsPreferenceKey.self,
value: [ItemBounds(id: item.id, bounds: frame, index: index)]
)
}
)
}
}
.padding(.horizontal, 2)
.coordinateSpace(name: "grid")
.onPreferenceChange(ItemBoundsPreferenceKey.self) { bounds in
itemBounds = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0) })
itemIndices = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0.index) })
}
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { gesture in
if isSelectionMode {
let location = gesture.location
if !isDragging {
startDragging(at: location, in: itemBounds)
}
updateSelection(at: location, in: itemBounds)
}
}
.onEnded { _ in
endDragging()
}
)
}
.coordinateSpace(name: "refresh")
}
you can see the .gesture(.... part. I realised that this DragGesture and ScrollView blocks each other (somehow only on iPhone 11)
highPriorityGesture also won't work.
When I change it with simultaneousGesture, scroll starts to work again.
BUT - since it's simultaneous, when multiple selection mode is activated, when I'm dragging my finger gallery also starts to scroll and it becomes a very unpleasant experience. After this issue I realised on native gallery iOS locks scroll when you are dragging for multiple selection and just when you release your finger you can scroll again even if the multiple selection mode is active.
I tried a million things, asked claude, chatgpt etc. etc.
Found some similar issues on stackoverflow but they were all related to iOS 18, not spesific to an iPhone. My app works fine on iOS 18 (15 Pro Max)
iOS 18 drag gesture blocks scrollview
Here are the some of the things I've tried: using highPriorityGesture and simultenousgesture together, tried to lock the scroll briefly while dragging, implement much complicated versions of these things with the help of claude, try to check if isSelectionMode is true or not
All of them broke other things/won't work.
Probably there's something pretty simple that I'm just missing; but iPhone 11 being the single problematic device confuses me. I don't want to mess too much with my already fragile logic.
I'm pretty new to Swift and SwiftUI. I'm making my first app for sorting a gallery with some extra features.
I was using my own iPhone for testing and just started testing my app on other Apple products.
Everything works fine on iPad Air M1, iPhone 15 Pro, iPhone 15 Pro Max, iPhone 13, iPhone XS (Simulator), and iPhone 11 Pro (Simulator). However, when I tried to show my app to a family member with an iPhone 11, I came across an issue.
Issue Description:
My app takes all photos from iPhone's native gallery, then you can sort it by some spesific filters and delete pictures. It just looks like the native gallery. (I can add photos later if needed) You can just scroll the gallery by swiping up and down. You can press the select button and start selecting pictures to delete.
I recently added a drag-to-select-multiple-pictures feature. This makes it feel more like the native iOS experience, eliminating the need to tap each picture individually.
However, on the iPhone 11, the moment you open the app, you can't scroll. Scrolling is completely locked. You can still select pictures by tapping or dragging, so it's not a touch area issue. The same issue persists on the iPhone 11 simulator.
And I think I found the problematic part in my (sadly messy) ContentView.swift file;
ScrollView {
RefreshControl(coordinateSpace: .named("refresh")) {
await viewModel.refreshMediaItems()
}
LazyVGrid(columns: gridColumns, spacing: UIDevice.current.userInterfaceIdiom == .pad ? 12 : 4) {
let items = viewModel.filteredItems(typeFilter: mediaTypeFilter, specialFilter: specialFilter)
ForEach(Array(zip(items.indices, items)), id: \.1.id) { index, item in
MediaThumbnailView(
item: item,
isSelected: selectedItems.contains(item.id),
viewModel: viewModel,
onLongPress: {
if !isSelectionMode {
toggleSelectionMode()
selectedItems.insert(item.id)
}
},
onTap: {
if isSelectionMode {
toggleSelection(item: item)
} else {
viewModel.selectItem(item)
}
}
)
.aspectRatio(1, contentMode: .fit)
.background(
GeometryReader { geometry in
let frame = geometry.frame(in: .named("grid"))
Color.clear.preference(
key: ItemBoundsPreferenceKey.self,
value: [ItemBounds(id: item.id, bounds: frame, index: index)]
)
}
)
}
}
.padding(.horizontal, 2)
.coordinateSpace(name: "grid")
.onPreferenceChange(ItemBoundsPreferenceKey.self) { bounds in
itemBounds = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0) })
itemIndices = Dictionary(uniqueKeysWithValues: bounds.map { ($0.id, $0.index) })
}
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { gesture in
if isSelectionMode {
let location = gesture.location
if !isDragging {
startDragging(at: location, in: itemBounds)
}
updateSelection(at: location, in: itemBounds)
}
}
.onEnded { _ in
endDragging()
}
)
}
.coordinateSpace(name: "refresh")
}
you can see the .gesture(.... part. I realised that this DragGesture and ScrollView blocks each other (somehow only on iPhone 11)
highPriorityGesture also won't work.
When I change it with simultaneousGesture, scroll starts to work again.
BUT - since it's simultaneous, when multiple selection mode is activated, when I'm dragging my finger gallery also starts to scroll and it becomes a very unpleasant experience. After this issue I realised on native gallery iOS locks scroll when you are dragging for multiple selection and just when you release your finger you can scroll again even if the multiple selection mode is active.
I tried a million things, asked claude, chatgpt etc. etc.
Found some similar issues on stackoverflow but they were all related to iOS 18, not spesific to an iPhone. My app works fine on iOS 18 (15 Pro Max)
iOS 18 drag gesture blocks scrollview
Here are the some of the things I've tried: using highPriorityGesture and simultenousgesture together, tried to lock the scroll briefly while dragging, implement much complicated versions of these things with the help of claude, try to check if isSelectionMode is true or not
All of them broke other things/won't work.
Probably there's something pretty simple that I'm just missing; but iPhone 11 being the single problematic device confuses me. I don't want to mess too much with my already fragile logic.
I'm currently building an App using a TabView as the main navigation method. In my app I would like to build a page similar to the Top Charts in the native App Store App with two lists side by side:
So far I came up with this code (simplified demo):
import SwiftUI
struct Demo: View {
var body: some View {
TabView {
Tab("Main Tab", systemImage: "tray.and.arrow.down.fill") {
NavigationStack {
HStack {
List {
Text("Left List")
}
List {
Text("Right List")
}
}
.navigationTitle("Demo")
.navigationBarTitleDisplayMode(.inline)
}
}
}
}
}
#Preview {
Demo()
}
However, I’m encountering a couple of issues:
• Scrolling to the top of the left list doesn’t trigger the toolbar background effect, and the content overlaps with the tabs in a strange way. Scrolling to the top of the right list works as expected.
• The navigation title is always hidden.
I haven’t been able to find a solution to these problems. What would be the correct approach? Thank you!
Looking for sample code 3d wireframe (with lines ) & polygons and should be able to rotate (set camera angles)
I tried sample code seems to be complicated & getting a BLANK screen
import SwiftUI
import SceneKit
struct SceneKitTest2: View {
var body: some View {
VStack{
Text("SceneKitTest2")
SceneView(scene: SCNScene(named:"Earth_1_12756.scn"), options: [.autoenablesDefaultLighting,.allowsCameraControl])
.frame(width:UIScreen.main.bounds.width,
height: UIScreen.main.bounds.height/2)
Spacer(minLength: 0)
}
}
}
Hello, my production app is experiencing some crashes according to app store analytics. I cannot seem to reproduce it.
According to Xcode Orginzer the app is crashing
10 SwiftUI 0x000000018ec372a0 PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:) + 332 (PlatformViewHost.swift:699)
Distributor ID: com.apple.AppStore
Hardware Model: iPhone13,4
Version: 2.0.3 (86)
AppStoreTools: 15E204
AppVariant: 1:iPhone13,4:16
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
OS Version: iPhone OS 17.4.1 (21E236)
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: SIGNAL 6 Abort trap: 6
Triggered by Thread: 0
Kernel Triage:
VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter
VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter
VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter
VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter
VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter
Thread 0 name:
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x00000001d1bd6974 __pthread_kill + 8 (:-1)
1 libsystem_pthread.dylib 0x00000001e56590ec pthread_kill + 268 (pthread.c:1717)
2 libsystem_c.dylib 0x0000000191627c14 __abort + 136 (abort.c:159)
3 libsystem_c.dylib 0x0000000191627b8c abort + 192 (abort.c:126)
4 libswiftCore.dylib 0x000000018832a690 swift::fatalErrorv(unsigned int, char const*, char*) + 136 (Errors.cpp:387)
5 libswiftCore.dylib 0x000000018832a6b0 swift::fatalError(unsigned int, char const*, ...) + 32 (Errors.cpp:395)
6 libswiftCore.dylib 0x0000000188324a08 getNonNullSrcObject(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*) + 256 (DynamicCast.cpp:144)
7 libswiftCore.dylib 0x0000000188326510 tryCastToObjectiveCClass(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InPro... + 88 (DynamicCast.cpp:510)
8 libswiftCore.dylib 0x0000000188324068 tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, sw... + 992 (DynamicCast.cpp:2281)
9 libswiftCore.dylib 0x0000000188323b14 swift_dynamicCast + 208 (CompatibilityOverrideRuntime.def:109)
10 SwiftUI 0x000000018ec372a0 PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:) + 332 (PlatformViewHost.swift:699)
11 SwiftUI 0x000000018ec36bf4 PlatformViewHost.updateEnvironment(_:viewPhase:) + 412 (PlatformViewHost.swift:690)
12 SwiftUI 0x000000018ec37bf8 PlatformViewHost.init(_:host:environment:viewPhase:importer:) + 808 (PlatformViewHost.swift:132)
13 SwiftUI 0x000000018ec36cf8 PlatformViewHost.__allocating_init(_:host:environment:viewPhase:importer:) + 92 (PlatformViewHost.swift:0)
14 SwiftUI 0x000000018ec0132c closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 444 (PlatformViewRepresentable.swift:559)
15 SwiftUI 0x000000018ec06c58 partial apply for closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 24 (<compiler-generated>:0)
16 SwiftUI 0x000000018ea26910 RepresentableContextValues.asCurrent<A>(do:) + 156 (RepresentableContextValues.swift:43)
17 SwiftUI 0x000000018ec01124 closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 176 (PlatformViewRepresentable.swift:558)
18 SwiftUI 0x000000018ec0104c closure #4 in closure #1 in PlatformViewChild.updateValue() + 128 (PlatformViewRepresentable.swift:557)
19 SwiftUI 0x000000018ec06b2c partial apply for closure #4 in closure #1 in PlatformViewChild.updateValue() + 24 (<compiler-generated>:0)
20 SwiftUI 0x000000018de7b7d0 closure #1 in _withObservation<A>(do:) + 44 (ObservationUtils.swift:26)
21 SwiftUI 0x000000018ec06b50 partial apply for closure #1 in _withObservation<A>(do:) + 24 (<compiler-generated>:0)
22 libswiftCore.dylib 0x0000000187fd0068 withUnsafeMutablePointer<A, B>(to:_:) + 28 (LifetimeManager.swift:82)
23 SwiftUI 0x000000018ebffbdc closure #1 in PlatformViewChild.updateValue() + 3040 (PlatformViewRepresentable.swift:556)
24 SwiftUI 0x000000018d5ecbf8 partial apply for implicit closure #1 in closure #1 in closure #1 in Attribute.init<A>(_:) + 32 (<compiler-generated>:0)
25 AttributeGraph 0x00000001b2150240 AG::Graph::UpdateStack::update() + 512 (ag-graph-update.cc:578)
26 AttributeGraph 0x00000001b2146f38 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 424 (ag-graph-update.cc:719)
27 AttributeGraph 0x00000001b2146810 AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 720 (ag-graph.cc:1429)
Environment
Mac mini M4 Pro
macOS: Version 15.1.1 (24B2091)
Xcode: Version 16.1 (16B40)
IME: Kotoeri, Google IME
Code description
struct ContentView: View {
@State var text = “”
@State var selection: TextSelection?
var body: some View {
VStack {
TextEditor(text: $text, selection: $selection)
}
.padding()
}
}
Issue Description
When built for macOS (not Catalyst, Designed for iPad) and typing “あ” in Japanese input, it crashes.
I tried using Kotoeri's Kana input, Kotoeri's Roman input, and Google IME, but the same error occurs and crashes in both cases.
There is no issue when using English input.
Errors
(input method 56222 com.apple.inputmethod.Kotoeri.KanaTyping) (1): Fatal error: String index is out of bounds
(input method 56338 com.apple.inputmethod.Kotoeri.RomajiTyping (1): Fatal error: String index is out of bounds
Swift/StringUTF16View.swift:368: Fatal error: String index is out of bounds
I'm trying to implement a 3 column NavigationSplitView in SwiftUI on macOS - very similar to Apple's own NavigationCookbook sample app - with the slight addition of multiple sections in the sidebar similar to how the Apple Music App has multiple sections in the sidebar.
Note: This was easily possible using the deprecated
NavigationLink(tag, selection, destination) API
The most obvious approach is to simply do something like:
NavigationSplitView(sidebar: {
List {
Section("Section1") {
List(section1, selection: $selectedItem1) {
item in
NavigationLink(item.label, value: item)
}
}
Section("Section2") {
List(section2, selection: $selectedItem2) {
item in
NavigationLink(item.label, value: item)
}
}
}
},
content: {
Text("Content View")
}, detail: {
Text("Detail View")
})
But unfortunately, this doesn't work - it doesn't seem to properly iterate over all of the items in each List(data, selection: $selected) or the view is strangely cropped - it only shows 1 item. However if the 1 item is selected, then the appropriate bindable selection value is updated. See image below:
If you instead use ForEach for enumerating the data, that does seem to work, however when you use ForEach, you loose the ability to track the selection offered by the List API, as there is no longer a bindable selection propery in the NavigationLink API.
NavigationSplitView(sidebar: {
List {
Section("Section1") {
ForEach(section1) {
item in
NavigationLink(item.label, value: item)
}
}
Section("Section2") {
ForEach(section2) {
item in
NavigationLink(item.label, value: item)
}
}
}
},
content: {
Text("Content View")
}, detail: {
Text("Detail View")
})
We no longer know when a sidebar selection has occurred.
See image below:
Obviously Apple is not going to comment on the expected lifespan of the now deprecated API - but I am having a hard time switching to the new NavigationLink with a broken sidebar implementation.
Hello,
I experienced a strange behavior with SceneView and a .frame() modifier. Here is a minimal example:
import SwiftUI
import SceneKit
struct MinimalSceneKitExample: View {
var simpleScene: SCNScene {
let scene = SCNScene()
let boxGeometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
let boxNode = SCNNode(geometry: boxGeometry)
boxNode.position = SCNVector3(0, 0, 0)
scene.rootNode.addChildNode(boxNode)
return scene
}
var body: some View {
SceneView(
scene: SCNScene(),
options: [.allowsCameraControl, .autoenablesDefaultLighting]
)
.frame(maxWidth: .infinity, maxHeight: 312.6)
}
}
This code turns the SceneView into a black view.
Only some height values are causing this behavior. For example the height value 312.3 is fine.
In my app, I'm using a dynamic height value that depends on the device's screen size which results in this behavior on some devices. Took me days to find this cause. So far integer values seem to always work which is what I will use as a quick fix for now.
Should I file a bug ticket for this?
I introduced lottie to toggle in my widget to show a transition animation, but found that the.json file wouldn't load. The loading_hc.json file is validated and exists in the widget target. Ask for help, thank you!
struct LottieView: UIViewRepresentable {
let animationName: String
func makeUIView(context: Context) -> LOTAnimationView {
let lotAnimationView = LOTAnimationView(name: animationName, bundle: .main)
lotAnimationView.contentMode = .scaleAspectFit
lotAnimationView.play()
return lotAnimationView
}
func updateUIView(_ uiView: LOTAnimationView, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
}
struct ControlToggleDisarmingStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
if configuration.isOn {
LottieView(animationName: "loading_hc.json").foregroundColor(.clear).frame(width: 24,height: 24)
} else {
Image("icon_disarm", bundle: Bundle.main).foregroundColor(.clear)
}
}
}
Live activity does not update its content's text color when the iPhone goes to sleep mode. Only the background color of live activity changes to dark mode but all the contents stay in light mode.
I have an app intent for interactive widgets.
when I touch the toggle, the app intent perform to request location.
func perform() async throws -> some IntentResult {
var mark: LocationService.Placemark?
do {
mark = try await AsyncLocationServive.shared.requestLocation()
print("[Widget] ConnectHandleIntent: \(mark)")
} catch {
WidgetHandler.shared.error = .locationUnauthorized
print("[Widget] ConnectHandleIntent: \(WidgetHandler.shared.error!)")
}
return .result()
}
@available(iOSApplicationExtension 13.0, *)
@available(iOS 13.0, *)
final class AsyncLocationServive: NSObject, CLLocationManagerDelegate {
static let shared = AsyncLocationServive()
private let manager: CLLocationManager
private let locationSubject: PassthroughSubject<Result<LocationService.Placemark, LocationService.Error>, Never> = .init()
lazy var geocoder: CLGeocoder = {
let geocoder = CLGeocoder()
return geocoder
}()
@available(iOSApplicationExtension 14.0, *)
@available(iOS 14.0, *)
var isAuthorizedForWidgetUpdates: Bool {
manager.isAuthorizedForWidgetUpdates
}
override init() {
manager = CLLocationManager()
super.init()
manager.delegate = self
}
func requestLocation() async throws -> LocationService.Placemark {
let result: Result<LocationService.Placemark, LocationService.Error> = try await withUnsafeThrowingContinuation { continuation in
var cancellable: AnyCancellable?
var didReceiveValue = false
cancellable = locationSubject.sink(
receiveCompletion: { _ in
if !didReceiveValue {
// subject completed without a value…
continuation.resume(throwing: LocationService.Error.emptyLocations)
}
},
receiveValue: { value in
// Make sure we only send a value once!
guard !didReceiveValue else {
return
}
didReceiveValue = true
// Cancel current sink
cancellable?.cancel()
// We either got a location or an error
continuation.resume(returning: value)
}
)
// Now that we monitor locationSubject, ask for the location
DispatchQueue.global().async {
self.manager.requestLocation()
}
}
switch result {
case .success(let location):
// We got the location!
return location
case .failure(let failure):
// We got an error :(
throw failure
}
}
// MARK: CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
defer {
manager.stopUpdatingLocation()
}
guard let location = locations.first else {
locationSubject.send(.failure(.emptyLocations))
return
}
debugPrint("[Location] location: \(location.coordinate)")
manager.stopUpdatingLocation()
if geocoder.isGeocoding {
geocoder.cancelGeocode()
}
geocoder.reverseGeocodeLocation(location) { [weak self] marks, error in
guard let mark = marks?.last else {
self?.locationSubject.send(.failure(.emptyMarks))
return
}
debugPrint("[Location] mark: \(mark.description)")
self?.locationSubject.send(.success(mark))
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
locationSubject.send(.failure(.errorMsg(error.localizedDescription)))
}
}
I found it had not any response when the app intent performed. And there is a location logo tips in the top left corner of phone screen.
I’m following the example code from Apple to implement the new iPadOS 18 TabView() with the new Tab(). While the tabbing itself is working fine, I can’t get it to show up a (large) navigation title in the sidebar (like the Home or Files app).
I’ve tried placing .navigationTitle("App Name") at the TabView, but that doesn’t work. Is it possible to do this in any way or is this not recommended to show?
TabView {
Tab("Overview", systemImage: "film") {
Text("Put a OverviewView here")
}
TabSection("Watch") {
Tab("Movies", systemImage: "film") {
Text("Put a MoviesView here")
}
Tab("TV Shows", systemImage: "tv") {
Text("Put a TVShowsView here")
}
}
TabSection("Listen") {
Tab("Music", systemImage: "music.note.list") {
Text("Put a MusicView here")
}
Tab("Podcasts", systemImage: "mic") {
Text("Put a PodcastsView here")
}
}
}
.tabViewStyle(.sidebarAdaptable)
.navigationTitle("App Name")
.navigationBarTitleDisplayMode(.large)
I know that there is also the .tabViewSidebarHeader() modifier, but that adds any view above the scroll view content. Neither does that easily allow to make it look like the regular navigation title, nor does it actually display in the navigation bar at the top, when scrolling down.
In iOS 18 widget, button is broken when it's has an accented desaturated image as content, the button's AppIntent will not trigger perform function.
checkout the code below:
`
struct WidgetExtEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("count:")
Text("\(WidgetExtAppIntent.count)")
HStack {
// button can not be tapped
Button(intent: WidgetExtAppIntent(action: "+1")) {
VStack {
Image(systemName: "plus.square.fill").resizable()
.widgetAccentedRenderingMode(.accentedDesaturated) // <-- here
.frame(width: 50, height: 50)
Text("Broken")
}
}.tint(.red)
// button can be tapped
Button(intent: WidgetExtAppIntent(action: "+1")) {
VStack {
Image(systemName: "plus.square.fill").resizable()
.widgetAccentedRenderingMode(.fullColor) // <-- here
.frame(width: 50, height: 50)
Text("OK").frame(width: 50, alignment: .center)
}
}.tint(.green)
}
.minimumScaleFactor(0.5)
}
}
}
`
check out the full demo project: ButtonInWidgetBrokenIOS18
I have a NavigationSplitView with all three columns, and NavigationLinks in the sidebar to present different Lists for the content column. When a list item is selected in the content view, I want to present a view in the detail view. Since different detail views should be presented for different content views, I represent state like this (some details omitted for space):
// Which detail view to show in the third column
enum DetailViewKind: Equatable {
case blank
case localEnv(RegistryEntry)
case package(SearchResult)
}
// Which link in the sidebar was tapped
enum SidebarMenuItem: Int, Hashable, CaseIterable {
case home
case localEnvs
case remoteEnvs
case packageSearch
}
// Binds to a DetailViewKind, defines the activate SidebarMenuItem
struct SidebarView: View {
@State private var selectedMenuItem: SidebarMenuItem?
@Binding var selectedDetailView: DetailViewKind
var body: some View {
VStack(alignment: .leading, spacing: 32) {
SidebarHeaderView()
Divider()
// Creates the navigationLinks with a SidebarMenuRowView as labels
SidebarMenuView(selectedMenuItem: $selectedMenuItem, selectedDetailView: $selectedDetailView)
Spacer()
Divider()
SidebarFooterView()
}
.padding()
.frame(alignment: .leading)
}
}
struct SidebarMenuRowView: View {
var menuItem: SidebarMenuItem
@Binding var selectedMenuItem: SidebarMenuItem?
@Binding var selectedDetailView: DetailViewKind
private var isSelected: Bool {
return menuItem == selectedMenuItem
}
var body: some View {
HStack {
Image(systemName: menuItem.systemImageName).imageScale(.small)
Text(menuItem.title)
Spacer()
}
.padding(.leading)
.frame(height: 24)
.foregroundStyle(isSelected ? Color.primaryAccent : Color.primary)
.background(isSelected ? Color.menuSelection : Color.clear)
.clipShape(RoundedRectangle(cornerRadius: 10))
.navigationDestination(for: SidebarMenuItem.self) { item in
navigationDestinationFor(menuItem: item, detailView: $selectedDetailView)
}
.onTapGesture {
if menuItem != selectedMenuItem {
selectedMenuItem = menuItem
}
}
}
}
// Determines which detail view to present
struct DetailView: View {
@Binding var selectedDetailView: DetailViewKind
var innerView: some View {
switch selectedDetailView {
case .blank:
AnyView(Text("Make a selection")
.font(.subheadline)
.foregroundStyle(.secondary)
.navigationSplitViewColumnWidth(min: 200, ideal: 350))
case .localEnv(let regEntry):
AnyView(EnvironmentDetailView(regEntry: regEntry))
case .package(let searchResult):
AnyView(PackageDetailView(searchResult: searchResult))
}
}
var body: some View {
innerView
}
}
struct ContentView: View {
@State private var detailView: DetailViewKind = .blank
var body: some View {
NavigationSplitView {
SidebarView(selectedDetailView: $detailView)
.navigationSplitViewColumnWidth(175)
} content: {
HomeView()
.navigationSplitViewColumnWidth(min: 300, ideal: 450)
}
detail: {
DetailView(selectedDetailView: $detailView)
}
}
}
My issue is that the detail view is not updated when the ContentView's detailView property is updated. I've verified that the value itself is changing, but the view is not. I searched around to see why this would be (this is my first Swift/SwiftUI application) and from what I gather a @Binding alone will not cause a view to be updated, that binding either needs to be used in the view hierarchy, or it needs to be stored as a @State property that gets updated when the binding value changes. I added a dummy @State property to DetailView and that still doesn't work, so I'm a little confused:
struct DetailView: View {
@Binding var selectedDetailView: DetailViewKind
@State private var dummyProp: DetailViewKind?
var innerView: some View {
switch selectedDetailView {
case .blank:
AnyView(Text("Make a selection")
.font(.subheadline)
.foregroundStyle(.secondary)
.navigationSplitViewColumnWidth(min: 200, ideal: 350))
case .localEnv(let regEntry):
AnyView(EnvironmentDetailView(regEntry: regEntry))
case .package(let searchResult):
AnyView(PackageDetailView(searchResult: searchResult))
}
}
var body: some View {
innerView.onChange(of: selectedDetailView) {
dummyProp = selectedDetailView
}
}
}
Any ideas?
Hi,
I have a form on an iPad App I'm developing and the form have text field at its bottom when tapping on it the keyboard cover those text fields how to solve this issue leave a hug gap at bottom of the form so text field jump to top when keyboard shows ?
Kind Regards