Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

Mapkit and swiftui
I have updated my map code so that now I have a region that is set as a state var in my strict. My map links to this state var. the problem is now I want to update my map based on my long and last variables that are passed to the struct is there a way to do this - going crazy trying to do this
3
0
4.8k
Jun ’20
Migrating existing SwiftUI apps to the new multi platform template
I have an iOS 13 app that I’m hoping to release soon that is written entirely in SwiftUI. If I was starting from scratch today, I’d obviously use the new multi platform template which looks awesome.... But since I’m not starting from scratch, what are the recommendations/best practices for existing apps? Is there a path for migrating existing apps to take advantage of the new app structure (below) when moving to iOS 14? @main struct HelloWorld: App { var body: some Scene { WindowGroup { Text(“Hello, world!”).padding() } } }
2
0
2.1k
Jun ’20
Prevent dismissal of sheet in SwiftUI
I'd like to emulate the behavior of UIViewController.isModalInPresentation in SwiftUI. In my first attempt, I defined the following view: struct ModalView<Content: View>: UIViewControllerRepresentable { 		var content: () -> Content 		func makeUIViewController(context: Context) -> UIHostingController<Content> { 				let controller = UIHostingController(rootView: content()) 				controller.isModalInPresentation = true 				return controller 		} 		func updateUIViewController(_ imagePickerController: UIHostingController<Content>, context: Context) {} } From my main app view, I then present the ModalView as a sheet: struct ContentView: View { 		@State 		var presentSheet: Bool = true 		var body: some View { 				Text("Hello, world!") 						.sheet(isPresented: $presentSheet) { 								ModalView { 										Text("Sheet") 								} 						} 		} } But the user is still able to dismiss the ModalView by swiping down. I would expect this sheet to be non-dismissible. Is anything like this supposed to work? If not, is there some other way to prevent the dismissal of a sheet in SwiftUI? The closest workaround I've found is to apply .highPriorityGesture(DragGesture()) to the content of the sheet, but swiping down with two fingers still works.
5
1
10k
Jun ’20
LinkDylibError when previewing SwiftUI view from a package.
I have two (local) Swift packages (both with a single library product): RemoteImage, which defines setImage(from:) function on UIImageView and SatelitUI package which directly depends on the first one and defines some views. But when I'm trying to preview views from the second package I'm getting the following error: linker command failed with exit code 1 (use -v to see invocation) LinkDylibError: Failed to build TrailerView.swift Linking failed: linker command failed with exit code 1 (use -v to see invocation) ld: warning: directory not found for option '-F/Applications/Xcode-beta.app/Contents/SharedFrameworks-iphonesimulator' Undefined symbols for architecture x86_64:   "(extension in RemoteImage):__C.UIImageView.setImage(from: Foundation.URL?) -> ()", referenced from:       (extension in SatelitUI_PreviewReplacement_TrailerView_2):SatelitUI.TrailerView.(previewupdate in _8C3731B0EF007627509BEEB93277D681)(with: SatelitUI.Trailer?) -> () in TrailerView.2.preview-thunk.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) Apparently, Xcode fails to link the library from the first package because it's dynamic. Static linking works as expected. It's a bug I believe?
2
1
2k
Jun ’20
Swift UI on iOS 14 not assigning new object to @State property
On iOS 13 I used to use optional @State properties to adapt views. In my case, the presented view would either create a new object (an assignment) if the state that is passed into it is nil, or edit the assignment if an assignment was passed in. This would be done in the action block of a Button and it worked beautifully. On iOS 14 / Xcode 12 this no longer seems to work. Given the following code which creates a new assignment and passes it into the editor view when the user taps a "New Assignment" button, the value of assignment remains nil. Is anyone else experiencing similar behaviour? struct ContentView: View { 		@Environment(\.managedObjectContext) var context 		@State var assignmentEditorIsPresented = false 		@State var assignment: Assignment? = nil 		var Body: some View { 				[...] 				Button("New Assignment", action: { 						self.assignment = Assignment(context: context) 						self.assignmentEditorIsPresented = true 				}) 				.sheet(isPresented: assignmentEditorIsPresented) { 						[...] 				} 		} } What's even weirder is that I tried adding a random piece of state, an Int, to this view and modifying it right before the assignment state (between lines 9 and 10) and it didn't change either.
21
4
13k
Jun ’20
Swiftui Custom Fonts not showing
Hello, My Custom fonts are not showing in SwiftUI. I am all up to date on all of my software and I have added my TTF's to a fonts folder in my collection. I also added the "Fonts provided by application" array type to my info.plist and the fonts as elements. Here is my code. I have no idea what I'm doing wrong. Is there a bug in the latest version of Swiftui? Text("Hello World") 			.font(.custom("VervelleScript-lgxR0", size: 36))
6
1
9.6k
Sep ’20
Lock widget for pro-users
Hi, I have added widgets to my iOS app and I would like to make this feature only accessible to "pro" users that have made a non-consumable in-app purchase. Currently, I am doing the following: I store an "isUnlocked" property in the Keychain after the purchase is made I read data to be displayed in the widget and here I also query the Keychain and store whether the widget is unlocked I have no refresh policy, but only change the widget data on a significant time change a different view is displayed when the app is locked Some dummy code snippets: func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) { &#9;&#9;let entry = readContents() &#9;&#9;let timeline = Timeline(entries: [entry], policy: .never) &#9;&#9;completion(timeline) } struct WidgetEntryView: View { &#9;&#9;let entry: Provider.Entry     @Environment(\.widgetFamily) var family     @ViewBuilder     var body: some View {         switch family {         case .systemSmall:             if !entry.isUnlocked {                 LockedWidgetView()             } else if let event = entry.event {                 SmallWidgetEventView(event: event)             } else {                 NoDataWidgetView()             } ... func applicationSignificantTimeChange(_ application: UIApplication) { &#9;&#9;if #available(iOS 14.0, *) { &#9;&#9;&#9;&#9;WidgetCenter.shared.reloadAllTimelines() &#9;&#9;} ... However, 2 unexpected things happen: the view is refreshed intraday (not only at midnight i.e. at significant time change) sometimes the LockedWidgetView is displayed. Especially the latter is problematic, because it gives false information to a user that has already made the in-app purchase. How can I achieve my goal of only displaying info when the user has made the in-app purchase? Thanks in advance. P.S. Although it would not have my preference, I would also find it acceptable if the widget is only shown as option to add once the purchase is made. In other words, I was considering changing the Widget itself: struct MyWidget: Widget {     private var supportedFamilies: [WidgetFamily] = isUnlocked() ? [.systemSmall, .systemMedium] : [] but I believe I cannot re-initialise the widget from the app when the user makes the in-app purchase, because the only refresh option that I have is WidgetCenter.shared.reloadAllTimelines()
7
0
3.5k
Oct ’20
Why does same code work differently within SwiftUI Life Cycle and UIKit App Delegate Life Cycle?
Introduction I created a simple app to test enabling Sign In with Google using Observable Objects in a SwiftUI Application. However, the app only functions properly (displaying the signed in user's name and email) with a UIKit App Delegate Life Cycle. The code of the App file for the SwiftUI life cycle and that of the app delegate and scene delegate files of the UIKit App Delegate life cycle should function identical; however, they do not. Project Code SwiftUI Lift Cycle AppDelegate import UIKit import SwiftUI import GoogleSignIn class AppDelegate: NSObject, UIApplicationDelegate { /* GoogleDelegate() is the observable object */ let googleDelegate = GoogleDelegate() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { GIDSignIn.sharedInstance()?.clientID = "CLIENT_ID" GIDSignIn.sharedInstance()?.delegate = googleDelegate return true } func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { return GIDSignIn.sharedInstance().handle(url) } } App @main struct WidgiTubeApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var window: UIWindow? { guard let scene = UIApplication.shared.connectedScenes.first, let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate, let window = windowSceneDelegate.window else {             return nil } return window } @Environment(\.scenePhase) private var scenePhase let googleDelegate = (UIApplication.shared.delegate as! AppDelegate).googleDelegate var body: some Scene { WindowGroup { GoogleSignInView() .environmentObject(googleDelegate) }.onChange(of: scenePhase) { (phase) in switch phase { case .active: GIDSignIn.sharedInstance().presentingViewController = window?.rootViewController window?.makeKeyAndVisible() case .inactive: case .background: default: } } } } Using the SwiftUI Life Cycle the User Is signed in; however, the information does not update in the SwiftUI view. (The view is identical between the SwiftUI Life Cycle and UIKit Application Delegate Life Cycle.) UIKit Application Delegate Life Cycle App Delegate DidFinishLaunchingWithOptions GIDSignIn.sharedInstance().clientID = "CLIENT_ID" GIDSignIn.sharedInstance().delegate = googleDelegate return true OpenURL return GIDSignIn.sharedInstance().handle(url) Scene Delegate SceneWillConnectTo let googleDelegate = (UIApplication.shared.delegate as! AppDelegate).googleDelegate let contentView = ContentView().environmentObject(googleDelegate) if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) GIDSignIn.sharedInstance()?.presentingViewController = window.rootViewController self.window = window window.makeKeyAndVisible() } Conclusion Due to this, I have identified that there must be some issue that occurs when adapting the UIKit App Delegate code to the SwiftUI App Code. However, I cannot identify what the issue between the two life cycles is. It is my understanding that anything possible with the UIKit Delegate life cycle should theoretically be possible with SwiftUI. In the mean time, of course, there is no issue continuing with the UIKit Delegate; however, I was hoping to create a SwiftUI app. If anyone could help me identify where the issue lays between these two different life cycles, I would greatly appreciate it. Thanks!
1
0
2.0k
Nov ’20
ScrollView won't scroll
Hello. I have successfully created a scrollview with several buttons that stack on top of one another. But the View won't scroll. What am i doing wrong here? scrollView = UIScrollView.init(frame: CGRect.zero) &#9;&#9;&#9;&#9;scrollView.translatesAutoresizingMaskIntoConstraints = false &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;self.view.addSubview(scrollView) &#9;&#9;&#9;&#9;var leadingAnchor = self.scrollView!.topAnchor &#9;&#9;&#9;&#9;for i in 0..<20{ &#9;&#9;&#9;&#9;&#9;&#9;let t_button = UIButton.init(frame: CGRect.zero) &#9;&#9;&#9;&#9;&#9;&#9;t_button.translatesAutoresizingMaskIntoConstraints = false &#9;&#9;&#9;&#9;&#9;&#9;t_button.backgroundColor = UIColor.blue &#9;&#9;&#9;&#9;&#9;&#9;scrollView.addSubview(t_button) &#9;&#9;&#9;&#9;&#9;&#9;NSLayoutConstraint.activate([ &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;t_button.topAnchor.constraint(equalTo: leadingAnchor, constant:5.0), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;t_button.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;t_button.heightAnchor.constraint(equalToConstant: 50.0), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;t_button.widthAnchor.constraint(equalToConstant: 75.0) &#9;&#9;&#9;&#9;&#9;&#9;]) &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;leadingAnchor = t_button.bottomAnchor &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;t_button.setTitle("Button \(i)", for: .normal) &#9;&#9;&#9;&#9;&#9;&#9;t_button.addTarget(self, action: #selector(scrollViewButtonAction(_:)), for: .touchUpInside) &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;NSLayoutConstraint.activate([ &#9;&#9;&#9;&#9;&#9;&#9;scrollView.topAnchor.constraint(equalTo: self.titleHeader.bottomAnchor, constant: 10.0), &#9;&#9;&#9;&#9;&#9;&#9;scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), &#9;&#9;&#9;&#9;&#9;&#9;scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), &#9;&#9;&#9;&#9;&#9;&#9;scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), &#9;&#9;&#9;&#9;])
4
0
7.4k
Dec ’20
What is the correct method for renaming a file in the app's container using the Swiftui 2.0 Document based template?
I've been using the new template for a document-based SwiftUI app. While you get a lot of file-management "for free" in the new template, as it stands in the iOS version users have to back out of the file to the file browser to change the filename. I want to create an opportunity for the user to rename the file while it is open. Here's a sample project focused on the issue: https://github.com/stevepvc/DocumentRenamer In the code, I've added to the template code a simple UI with a textfield for the user to enter a new name. When the user hits the "rename" button, the app checks to see if the URL with that name component is available, appending a suffix if necessary to create a target url. func getTargetURL() -> URL { &#9;&#9;let baseURL&#9;=&#9;self.fileurl.deletingLastPathComponent() &#9;&#9;print("filename: \(self.filename)") &#9;&#9;print("fileURL: \(self.fileurl)") &#9;&#9;print("BaseURL: \(baseURL)") &#9;&#9;var target = URL(fileURLWithPath: baseURL.path + "/\(filename).exampletext") &#9;&#9;var nameSuffix = 1 &#9;&#9; &#9;&#9;while (target as NSURL).checkPromisedItemIsReachableAndReturnError(nil) { &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;target = URL(fileURLWithPath: baseURL.path + "/\(filename)-\(nameSuffix).sermon") &#9;&#9;&#9;&#9;print("Checking: \(target)") &#9;&#9;&#9;&#9;nameSuffix += 1 &#9; } &#9;&#9;print("Available Target: \(target)") &#9;&#9;return target } It then attempts to rename the file, and this is when I am stuck. I have tried several methods, most recently the following: func changeFilename(){ &#9;&#9;let target&#9;= getTargetURL() &#9;&#9;var rv = URLResourceValues() &#9;&#9;let newFileName = target.deletingPathExtension().lastPathComponent &#9;&#9;rv.name = newFileName &#9;&#9;do { &#9;&#9;&#9;&#9;if fileurl.startAccessingSecurityScopedResource(){ &#9;&#9;&#9;&#9;&#9;&#9;try fileurl.setResourceValues(rv) &#9;&#9;&#9;&#9;&#9;&#9;fileurl.stopAccessingSecurityScopedResource() &#9;&#9;&#9;&#9;} &#9;&#9;} catch { &#9;&#9;&#9;&#9;print("Error:\(error)") &#9;&#9;} } But I keep getting the following error whenever I run the app on a device: Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “Untitled” in the folder “DocumentRenamer”." I have also tried this without the startAccessingSecurityScopedResource() check, and alternatively have tried creating a helper class as follows: class FileMover: NSObject { func moveFile(originalURL: URL, updatedURL:URL) -> Bool { &#9;&#9;let coordinator = NSFileCoordinator(filePresenter: nil) &#9;&#9;var writingError: NSError? = nil &#9;&#9;var success : Bool = true &#9;&#9;print("moving file") &#9;&#9;coordinator.coordinate(writingItemAt: originalURL, options: NSFileCoordinator.WritingOptions.forMoving, error: &writingError, byAccessor: { (coordinatedURL) in &#9;&#9;&#9;&#9;do { &#9;&#9;&#9;&#9;&#9;&#9;try FileManager.default.moveItem(at: coordinatedURL, to: updatedURL) &#9;&#9;&#9;&#9;&#9;&#9;success = true &#9;&#9;&#9;&#9;&#9;&#9;print("file moved") &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;} catch { &#9;&#9;&#9;&#9;&#9;&#9;print(error) &#9;&#9;&#9;&#9;&#9;&#9;success = false &#9;&#9;&#9;&#9;} &#9;&#9;}) return success &#9;&#9; } } But using this method locks up the app entirely. What is the correct method for renaming a file in the app's container, particularly using the new Swiftui Document based template?
3
3
3.4k
Dec ’20
LazyVGrid (embedded in a List) does not resize automatically when content increases and layout changes
I have a List in a sidebar style which contains a LazyVGrid and a Section with a simple list contents. Every thing works well except when content increases and layout changes (from two columns to one column) for the LazyVGrid with editMode changing to .active ... LazyVGrid does not expand/resize when the content increases (the increased content gets clipped)...but does when user expands/folds on the section below :(. However LazyVGrid resizes to show the entire content when the content shrinks with editMode reverting to .inactive Note: If I replace the List with a ScrollView...lazyVGrid resizes perfectly when content increases in editMode = .active....but then I would lose all the Sidebar and List characteristics for the Section below :( Also, looks like .onMove is not supported in LazyVGrids Any pointers to solve the LazyVGrid (embedded in a List) not resizing or expanding when content increases ... will be deeply appreciated. var body: some View {         List {             LazyVGrid(columns: editMode?.wrappedValue == .active ? singleColumn : twoColumns, alignment: .leading, spacing: 10) {                 ForEach(editMode?.wrappedValue == .active ? allDashItems : selectedDashItems) { dashitem in                     DashItemCell(dashitem)                                         }                 .onMove(perform: moveDashItem)                 .environment(\.editMode, editMode)             }             Section(header: Text("Bottom Section")) {                     ForEach (sectionList)&#9;{ item in                         ListItemCell(item)                     }                     .onDelete(perform: deleteFolder)                     .onMove(perform: moveFolder)                 }         }         .listStyle(SidebarListStyle()) }
1
1
1.6k
Jan ’21
Setting launch screen image through info.plist - image stretches to cover full screen
I am developing an app in swiftUI using Xcode 12.3, deployment target iOS 14.0. The launch screen is setup through info.plist by specifying 'background color' and 'image name'. The file used in 'image name' is from Assets catalog. (PNG format, size300 x 300 and corresponding @2x and @3x resolutions) What I have observed, when the app is installed for the first time the launch image is centered and have original resolutions but all subsequent launches show launch images stretched to cover full screen. Any ideas why this is happening and how to have more consistent behavior either way? I have tried 'respect safe area' option but it does not make a difference. Thank you.
12
2
13k
Jan ’21
How do I pass a binding to a focus state?
In a SwiftUI lab, I was asking about setting the focus state down a view hierarchy. The answer I got was to pass the focus state down the views as a binding. Conceptually, that made sense, so I moved on to other questions. But now that I am trying to implement it, I am having problems. In the parent view, I have something like this: @FocusState private var focusElement: UUID? Then I am setting a property like this in the child view: @Binding var focusedId: UUID? When I try to create the detail view, I'm trying this: DetailView(focusedId: $focusElement) But this doesn't work. The error I get is: Cannot convert value of type 'FocusState<UUID?>.Binding' to expected argument type 'Binding<UUID?>' What is the right way to pass down the focus state to a child view so that it can update back up to the parent view? I am trying to update from one child view, and have a TextField in a sibling view get focus.
2
0
13k
Jun ’21
AsyncImage - Cancelled Loading before View is Visible
I have been playing around with the new AsyncImage Api in SwiftUI I am using the initialiser that passes in a closure with the AsyncImagePhase, to view why an image may not load, when I looked at the error that is passed in if the phase is failure, the localised description of the error is "Cancelled" but this is happening before the view is being displayed. I am loading these images in a list, I imagine I am probably doing something which is causing the system to decide to cancel the loading, but I cannot see what. Are there any tips to investigate this further?
15
8
13k
Jun ’21
Accessing an actor's isolated state from within a SwiftUI view
I'm trying to understand a design pattern for accessing the isolated state held in an actor type from within a SwiftUI view. Take this naive code: actor Model: ObservableObject { @Published var num: Int = 0 func updateNumber(_ newNum: Int) { self.num = newNum } } struct ContentView: View { @StateObject var model = Model() var body: some View { Text("\(model.num)") // <-- Compiler error: Actor-isolated property 'num' can not be referenced from the main actor Button("Update number") { Task.detached() { await model.updateNumber(1) } } } } Understandably I get the compiler error Actor-isolated property 'num' can not be referenced from the main actor when I try and access the isolated value. Yet I can't understand how to display this data in a view. I wonder if I need a ViewModel that observes the actor, and updates itself on the main thread, but get compile time error Actor-isolated property '$num' can not be referenced from a non-isolated context. class ViewModel: ObservableObject { let model: Model @Published var num: Int let cancellable: AnyCancellable init() { let model = Model() self.model = model self.num = 0 self.cancellable = model.$num // <-- compile time error `Actor-isolated property '$num' can not be referenced from a non-isolated context` .receive(on: DispatchQueue.main) .sink { self.num = $0 } } } Secondly, imagine if this code did compile, then I would get another error when clicking the button that the interface is not being updated on the main thread...again I'm not sure how to effect this from within the actor?
3
2
9.5k
Aug ’21
@AppStorage with Date in SwiftUI
Hello I want to be able to save Date in @AppStorage, and it works however I was wondering what was the difference between these two extensions, which one is better and why? extension Date: RawRepresentable { static var dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .long return formatter }() public var rawValue: String { Date.dateFormatter.string(from: self) } public init?(rawValue: String) { self = Date.dateFormatter.date(from: rawValue) ?? Date() } } and extension Date: RawRepresentable { private static let formatter = ISO8601DateFormatter() public var rawValue: String { Date.formatter.string(from: self) } public init?(rawValue: String) { self = Date.formatter.date(from: rawValue) ?? Date() } } Thank You!
5
0
6.0k
Aug ’21
iOS App shows blank screen after migrating to SwiftUI Lifecycle
This question was originally posted to StackOverflow, but I found it more suitable to be placed here. Was working on migrating one of my app from AppDelegate lifecycle to SwiftUI lifecycle according to this question. After following all the steps, The simulator simply shows a blank screen (the app does not launch at all): There is no log in the console. However, if the app is removed from the simulator (or device) and reinstalled, it will launch the new SwiftUI lifecycle correctly. So there seems to be some problem with scene caching that causes iOS to be confused after the migration. Am I missing something during the migration?
2
0
2.8k
Sep ’21
Contents of .sheet() are being redrawn after dismiss and not presenting
Use Case If you have a ContentView that displays a pausable view based on a @State private var presentSheet = false property that is also used to present a .sheet(isPresented: $presentSheet) if: the property is sent to the PausableView(isPaused: presentSheet) as a normal property, the body of the ContentView and the body of the sheet is being redrawn when the sheet is dismissed the property is sent to the PausableView(isPaused: $presentSheet) as a @Binding, the body of the ContentView and the body of the sheet is NOT redrawn when the sheet is dismissed Is this normal behavior? The ContentView body makes sense to change, but is the sheet's body also supposed to be redrawn when the sheet is not presenting anymore after dismiss? Sample Project A sample project created in Xcode 13 is available here: https://github.com/clns/SwiftUI-sheet-redraw-on-dismiss. I noticed the same behavior on iOS 14 and iOS 15. There are also 2 animated gifs showing the 2 different behaviors in the GitHub project. The relevant code is in ContentView.swift: import SwiftUI struct DismissingView: View { @Binding var isPresented: Bool var body: some View { if #available(iOS 15.0, *) { print(Self._printChanges()) } else { print("DismissingView: body draw") } return VStack { Button("Dismiss") { isPresented.toggle() } Text("Dismissing Sheet").padding() }.background(Color.white) } } struct PausableView: View { var isPaused: Bool // @Binding var isPaused: Bool private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() @State private var counter = 0 var body: some View { Text("Elapsed seconds: \(counter)") .onReceive(timer) { _ in counter += isPaused ? 0 : 1 } } } struct ContentView: View { @State private var presentSheet = false var body: some View { if #available(iOS 15.0, *) { print(Self._printChanges()) } else { print("ContentView: body draw") } return VStack{ Button("Show Sheet") { presentSheet.toggle() } Text("The ContentView's body along with the .sheet() is being redrawn immediately after dismiss, if the @State property `presentSheet` is used anywhere else in the view - e.g. passed to `PausableView(isPaused:presentSheet)`.\n\nBut if the property is passed as a @Binding to `PausableView(isPaused:$presentSheet)`, the ContentView's body is not redrawn.").padding() PausableView(isPaused: presentSheet) // PausableView(isPaused: $presentSheet) } .sheet(isPresented: $presentSheet) { DismissingView(isPresented: $presentSheet) .background(BackgroundClearView()) // to see what's happening under the sheet } } }
2
1
1.6k
Oct ’21