I have discovered a strange phenomenon about iOS18.1.1. I set a logo as the titleView in my navigationBar, and then when I added a view to the navigationBar and pushed it to another page before popping it back up, I found that the view hierarchy of the navigationBar would change in a very short time. In this short time, the logo would cover the view. I did not find this phenomenon on devices below iOS18.1.1. I would like to know what changes have occurred in iOS18.1.1 that caused the view hierarchy to change during the pop process. I hope someone can help me. Thank you very much
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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!
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.
Topic:
UI Frameworks
SubTopic:
SwiftUI
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.
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.
Topic:
UI Frameworks
SubTopic:
SwiftUI
VStack {
TextField("Enter a location", text: $addressText)
.textInputSuggestions {
ForEach(suggestedVenues.filter { $0.name.lowercased().contains(addressText.lowercased()) || $0.address.lowercased().contains(addressText.lowercased()) }, id: \.id) { venue in
Label(venue.name, systemImage: venue.image)
.textInputCompletion(venue.address)
}
}
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Spacer()
}
.padding()
}
not working in IOS 18.2 ??
'textInputSuggestions' is unavailable in iOS
Topic:
UI Frameworks
SubTopic:
SwiftUI
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
Topic:
UI Frameworks
SubTopic:
SwiftUI
I am trying to upload a ZIP file, created by compressing other files in iCloud Drive through the Files app, using UIDocumentPicker. However, errors like those described in Test 1 and Test 2 in the sample code are occurring.
import UIKit
class ViewController: UIViewController,UIDocumentPickerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func openDocumentPicker(_ sender: Any) {
// Test 1
// let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.item], asCopy: true)
// When clicking the "Open" button, there is no response, and the following error occurs.
/*
Failed to copy the imported file into the local container ((null))
Tried to call delegate -documentBrowser:didPickDocumentURLs: with an empty array of items. This indicates the items failed to be prepared and materialized on disk: (
"<DOCItemBookmark: 0x303ad2fc0> FPItem=(null)"
)
*/
// Test 2
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.item])
// When using the regular mode instead of the copy mode,
// the "Open" button works, and the selectedFileURL is correctly retrieved.
// However, even after using startAccessingSecurityScopedResource,
// attempting to read the file results in the following error.
/*
Error reading file: Error Domain=NSCocoaErrorDomain Code=257 "The file “archive 4.zip” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/samplefiles/archive 4.zip, NSURL=file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/%E1%84%89%E1%85%A2%E1%86%B7%E1%84%91%E1%85%B3%E1%86%AF%E1%84%91%E1%85%A1%E1%84%8B%E1%85%B5%E1%86%AF/%E1%84%8B%E1%85%A1%E1%84%8F%E1%85%A1%E1%84%8B%E1%85%B5%E1%84%87%E1%85%B3%204.zip, NSUnderlyingError=0x300bedbf0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}
*/
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = true
self.present(documentPicker, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard urls.isEmpty == false else {
print("no urls")
return
}
//Test2
for selectedFileURL in urls {
// Start accessing the security-scoped resource
if selectedFileURL.startAccessingSecurityScopedResource() {
defer { selectedFileURL.stopAccessingSecurityScopedResource() }
// Perform operations on the file
do {
let fileCoordinator = NSFileCoordinator()
var error: NSError?
fileCoordinator.coordinate(readingItemAt: selectedFileURL, options: [], error: &error) { (newURL) in
do {
let fileData = try Data(contentsOf: newURL)
// Process the file data
print("File data read successfully")
} catch {
print("Error reading file: \(error)")
}
}
if let error = error {
print("Error coordinating file access: \(error)")
}
} catch {
print("Error reading file: \(error)")
}
} else {
print("Failed to access security-scoped resource")
}
}
}
It seems that there might be an issue with the compressed ZIP file. How can this be resolved?
Topic:
UI Frameworks
SubTopic:
General
iOS 18 broke some functionality in my Objective-C app with regard to using the DatePicker.
The key lines are as follows:
datePicker.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:timezoneOffset];
datePicker.date = [NSDate date];
When timezoneOffset is -29380, the value for San Francisco, the Date Picker is a whole MONTH off. It shows November instead of December.
But when it is -29359, the value for Seattle, which is in the same time zone (PST), it shows the correct month. In fact, even towns surrounding San Francisco usually return the correct value. Some other cities in other time zones also cause the Date Picker to be a month off.
Dear Sirs,
I'm searching for the most straightforward way to identify the root of a "Publishing changes from within view updates is not allowed, this will cause undefined behavior." warning. It is a complex SwiftUI project and I think there should be a better way than just try and error with disabling/removing and enabling/adding different screen elements to check if the warning still is shown. I tried to set a symbolic breakpoint for "os_log" in my XCode project and indeed this is triggered right before the warning appears but the callstack doesn't give me a direct hint to the part of my code which causes this warning. What would be the most direct way and is there something like an exception handler in such cases?
Thanks and best regards,
Johannes
Our MacOS app has for some time been able to create so-called "add-on" services, which are dynamically written to individual bundles in ~/Library/Services/ (as opposed to being statically defined in the app's Info.plist). These worked fine for a long time until recently. They still appear in other app Services menus, but do not get as far as calling the specified instance method in our app. Does anyone know if add-on services are no longer supported? Perhaps due to some new security constraint? The documentation on app services in general seems to be out of date.
I did try copying the add-on service definition from the add-on plist into the app's Info.plist. That seemed to work, so the basic specification doesn't seem to have changed.
Topic:
UI Frameworks
SubTopic:
AppKit
Hi there,
I have a TabView in page style. Inside that TabView I have a number of views, each view is populated with a model object from an array. The array is iterated to provide the chart data.
Here is the code:
TabView(selection: $displayedChartIndex) {
ForEach((0..<data.count), id: \.self) { index in
ZStack {
AccuracyLineView(graphData: tabSelectorModel.lineChartModels[index])
.padding(5)
}
.tag((index))
}
}
.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
I am seeing odd behaviour, as I swipe left and right, occasionally the chart area shows the chart from another page in the TabView. I know the correct view is being shown as there are text elements.
See the screenshot below. The screen on the right is running iOS 17.2 and this works correctly. The screen on the left is running iOS 17.4 and the date at the top is correct which tells me that the data object is correct. However the graph is showing a chart from a different page. When I click on the chart on the left (I have interaction enabled) then it immediately draws the correct chart. If I disable the interaction then I still get the behaviour albeit the chart never corrects itself because there is no interaction!
I can reproduce this in the 17.4 simulator and it is happening in my live app on iOS17.4. This has only started happening since iOS 17.4 dropped and works perfectly in iOS 17.2 simulator and I didn't notice it in the live app when I was running 17.3.
Is this a bug and/or is there a workaround?
For info this is the chart view code, it is not doing anything clever:
struct AccuracyLineView: View {
@State private var selectedIndex: Int?
let graphData: LineChartModel
func calcHourMarkers (maxTime: Int) -> [Int] {
let secondsInDay = 86400 // 60 * 60 * 24
var marks: [Int] = []
var counter = 0
while counter <= maxTime {
if (counter > 0) {
marks.append(counter)
}
counter += secondsInDay
}
return marks
}
var selectedGraphMark: GraphMark? {
var returnMark: GraphMark? = nil
var prevPoint = graphData.points.first
for point in graphData.points {
if let prevPoint {
if let selectedIndex, let lastPoint = graphData.points.last, ((point.interval + prevPoint.interval) / 2 > selectedIndex || point == lastPoint) {
if point == graphData.points.last {
if selectedIndex > (point.interval + prevPoint.interval) / 2 {
returnMark = point
} else {
returnMark = prevPoint
}
} else {
returnMark = prevPoint
break
}
}
}
prevPoint = point
}
return returnMark
}
var body: some View {
let lineColour:Color = Color(AppTheme.globalAccentColour)
VStack {
HStack {
Image(systemName: "clock")
Text(graphData.getStartDate() + " - " + graphData.getEndDate()) // 19-29 Sept
.font(.caption)
.fontWeight(.light)
Spacer()
}
Spacer()
Chart {
// Lines
ForEach(graphData.points) { item in
LineMark(
x: .value("Interval", item.interval),
y: .value("Offset", item.timeOffset),
series: .value("A", "A")
)
.interpolationMethod(.catmullRom)
.foregroundStyle(lineColour)
.symbol {
Circle()
.stroke(Color(Color(UIColor.secondarySystemGroupedBackground)), lineWidth: 4)
.fill(AppTheme.globalAccentColour)
.frame(width: 10)
}
}
ForEach(graphData.trend) { item in
LineMark (
x: .value("Interval", item.interval),
y: .value("Offset", item.timeOffset)
)
.foregroundStyle(Color(UIColor.systemGray2))
}
if let selectedGraphMark {
RuleMark(x: .value("Offset", selectedGraphMark.interval))
.foregroundStyle(Color(UIColor.systemGray4))
}
}
.chartXSelection(value: $selectedIndex)
.chartXScale(domain: [0, graphData.getMaxTime()])
}
}
}
I am able to retrieve the text in the input field by doing:
let contextBeforeInput = textDocumentProxy.documentContextBeforeInput ?? ""
let contextAfterInput = textDocumentProxy.documentContextAfterInput ?? ""
let fullText = contextBeforeInput + contextAfterInput
However, when I'm pasting text into the input field, textDocumentProxy.documentContextBeforeInput refuses to return the entire text from the input field but instead only returns the last two sentences.
I have tried this with the input fields in WhatsApp, Signal, and Telegram and it's all the same, so it doesn't seem to be caused by the specific app.
At first I thought it was a limitation imposed by Apple but other third party keyboard extensions such as Grammarly are able to pick up the whole pasted text from the input field, so how are they doing it?
Topic:
UI Frameworks
SubTopic:
UIKit
For a UIKit app based on scenes (UIScene), is it safe to reference UserDefaults in code that is executed from UIApplicationDelegate/application(_: didFinishLaunchingWithOptions:) ?
I've read that in iOS 15, there were undocumented scenarios involving app prewarming that would cause UserDefaults reads to fail within a window of time after device reboots, as described at https://christianselig.com/2024/10/beware-userdefaults/
The failure mode is that an app would be released, and months later, a small fraction of users would report failures consistent with UserDefaults reads unexpectedly returning nil, causing a loss of data. The user experience is bad, and debugging this behavior is then challenging because of how rarely it occurs.
Apple's https://developer.apple.com/documentation/uikit/app_and_environment/responding_to_the_launch_of_your_app/about_the_app_launch_sequence#3894431 seems to suggest that prewarming only executes an app "up until, but not including when main() calls UIApplicationMain(_:_:_:_:), but https://stackoverflow.com/questions/71025205/ios-15-prewarming-causing-appwilllaunch-method-when-prewarm-is-done documents that UIApplicationDelegate/application(_: didFinishLaunchingWithOptions:) has in fact been observed executing during app prewarming in scene-based apps.
So, my question: In an app based on scenes, if I'd like to reference UserDefaults within UIApplicationDelegate/application(_: didFinishLaunchingWithOptions:), when is it safe to do this?
I'm guessing the answer is one of these:
Never.
Only in apps that don't support scenes.
Only in iOS 16 or later.
Only in IOS 17 or later.
Is it guaranteed safe to reference UserDefaults in UIWindowSceneDelegate/scene(_:willConnectTo:options:) or later?
Is there documentation from Apple regarding this issue?
Thank you.
I have an app that acts as an agent (no dock/app, just menu bar icon). When the icon is clicked, I show a popover with a small user interface.
This works great, however, there is an issue. When a certain app is in full-screen and then my menu bar icon is clicked, the user interface shows just fine, until the mouse is moved outside the menu bar - then the user interface stays but the menu bar dismisses and closes.
Is there a way to keep the menu bar open, like when clicking on Control Center, in full-screen apps?
This is how I open my popover:
if let button = statusItem.button {
if popover.isShown {
self.popover.performClose(sender)
} else {
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
popover.contentViewController?.view.window?.makeKey()
}
}
}
When I try to launch a ShareLink from within a fullScreenCover, I get the following error:
Attempt to present <UIActivityViewController: 0x105e6a400> on <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x1053a37c0> (from <_TtGC7SwiftUI19UIHostingControllerVVS_7TabItem8RootView_: 0x105eb8a00>) which is already presenting <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x114890000>
Seems like a bug, has anyone else encountered this or found a way around it?
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?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I’m building a SwiftUI app where the struct AppGroup is identified by a UUID and stored in a dictionary. My Task model has appGroupId: UUID?. In TaskDetailView, I create a custom Binding<AppGroup> from the store, then navigate to AppGroupDetailView. However, when I tap the NavigationLink, the console spams logs, CPU hits 100%, and it never stabilizes.
Relevant Code
AppGroupStore (simplified)
class AppGroupStore: ObservableObject {
@Published var appGroupsDict: [UUID: AppGroup] = [:]
func updateAppGroup(_ id: UUID, appGroup: AppGroup) {
appGroupsDict[id] = appGroup
}
// Returns a binding so views can directly read/write the AppGroup by id
func getBinding(withId id: UUID?) -> Binding<AppGroup> {
Binding(
get: {
if let id = id {
return self.appGroupsDict[id] ?? .empty
}
return .empty
},
set: { newValue in
print("New value set for \(newValue.name)")
self.updateAppGroup(newValue.id, appGroup: newValue)
}
)
}
// ...
}
AppGroup is a simple struct:
struct AppGroup: Identifiable, Codable {
let id: UUID
var name: String
var apps: [String]
static let empty = AppGroup(id: UUID(), name: "Empty", apps: [])
}
TaskDetailView (main part)
struct TaskDetailView: View {
@Binding var task: ToDoTask // has task.appGroupId: UUID?
@EnvironmentObject var appGroupStore: AppGroupStore
var body: some View {
let appGroup = appGroupStore.getBinding(withId: task.appGroupId)
print("Task load") // prints infinitely, CPU 100%
return List {
// ...
NavigationLink(destination: AppGroupDetailView(appGroup: appGroup)) {
Text(appGroup.wrappedValue.name)
}
}
.navigationTitle(task.name)
}
}
AppGroupDetailView (simplified)
struct AppGroupDetailView: View {
@Binding var appGroup: AppGroup
// ...
var body: some View {
List {
ForEach(appGroup.apps, id: \.self) { app in
Text(app)
}
}
.navigationTitle(appGroup.name)
}
}
Symptoms:
Tapping the NavigationLink leads to infinite “Task load” logs and 100% CPU usage.
The set closure (“New value set for...”) is never called, so it’s not repeatedly writing.
If I replace the Binding<AppGroup> with a read-only approach (just accessing the dictionary), it does not get stuck.
Question:
What might cause SwiftUI to keep re-rendering the body indefinitely, even if my custom get closure doesn’t explicitly mutate the state? Are there known pitfalls when using a dictionary-based store and returning a Binding like this?
Any help is much appreciated!
Thanks in advance for your insights!
I'm trying to make the side bar menu on my tvOS app have the same behavior of Apple's tvOS App. I would like to have the side menu collapsed at the cold start of the app. I'm trying to achieve this by using the defaultFocus view modifier, which should make the button inside the TabView focused at the start of the app. But no matter what I do, the side bar always steels the focus from the inside button.
struct ContentView: View {
enum Tabs {
case viewA
case viewB
}
enum ScreenElements {
case button
case tab
}
@FocusState private var focusedElement: ScreenElements?
@State private var selectedTab: Tabs? = nil
var body: some View {
Group {
TabView(selection: $selectedTab) {
Tab("View A", image: "square", value: .viewA) {
Button("View A Button", action: {})
.frame(maxWidth: .infinity, alignment: .center)
.focused($focusedElement, equals: .button)
}
}
.tabViewStyle(.sidebarAdaptable)
.focused($focusedElement, equals: .tab)
}
.defaultFocus($focusedElement, .button, priority: .userInitiated)
}
}
Is there a way to start the side bar menu collapsed at the start up of the app?
I must be missing something here. I want to put a landscape image in a geometry reader that contains a ZStack that contains an image and an overlay centred on top of the Image.
I would like the ZStack and GeoReader's sizes to be the size of Image. (ie I want geometry.size to be the size of the image, which can be used to control the offset of the overlay's position.)
Unfortunately the ZStack also includes the space above the image (ie the top safeArea) and the GeometryReader also includes all the space below the Image. (so geometry.size.height is greater than the height of Image)
I've gone down rabbit holes of adding other items above/below, but I don't seem to be able to prevent the GeometryReader from being vertically greedy.
eg the Text(" ") above the ZStack in the VStack solves the ZStack claiming the top safe area. But adding Text(" ") below the ZStack does not prevent the GeometryReader from claiming more vertical space below the image.
Any/all guidance greatly appreciated.
struct ContentView: View {
var body: some View {
VStack {
// Text(" ")
GeometryReader { geometry in
ZStack {
Image(
uiImage: .init(imageLiteralResourceName: "LandscapeSample")
)
.resizable()
.aspectRatio(contentMode: .fit)
Text("Hello, world!")
.background(.white)
}
.background(.red)
}
.background(.blue)
// Text(" ")
}
}
}