Present a new view in SwiftUI
To show a modal (iOS 13 style)
You just need a simple sheet
with the ability to dismiss itself:
struct ModalView: View {
@Binding var presentedAsModal: Bool
var body: some View {
Button("dismiss") { self.presentedAsModal = false }
}
}
And present it like:
struct ContentView: View {
@State var presentingModal = false
var body: some View {
Button("Present") { self.presentingModal = true }
.sheet(isPresented: $presentingModal) { ModalView(presentedAsModal: self.$presentingModal) }
}
}
Note that I passed the presentingModal
to the modal so you can dismiss it from the modal itself, but you can get rid of it.
To make it REALLY present fullscreen
(Not just visually)
You need to access to the ViewController
. So you need some helper containers and environment stuff:
struct ViewControllerHolder {
weak var value: UIViewController?
}
struct ViewControllerKey: EnvironmentKey {
static var defaultValue: ViewControllerHolder {
return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)
}
}
extension EnvironmentValues {
var viewController: UIViewController? {
get { return self[ViewControllerKey.self].value }
set { self[ViewControllerKey.self].value = newValue }
}
}
Then you should use implement this extension:
extension UIViewController {
func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
toPresent.modalPresentationStyle = style
toPresent.rootView = AnyView(
builder()
.environment(\.viewController, toPresent)
)
NotificationCenter.default.addObserver(forName: Notification.Name(rawValue: "dismissModal"), object: nil, queue: nil) { [weak toPresent] _ in
toPresent?.dismiss(animated: true, completion: nil)
}
self.present(toPresent, animated: true, completion: nil)
}
}
Finally
you can make it fullscreen
like:
struct ContentView: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
var body: some View {
Button("Login") {
self.viewControllerHolder?.present(style: .fullScreen) {
Text("Main") // Or any other view you like
// uncomment and add the below button for dismissing the modal
// Button("Cancel") {
// NotificationCenter.default.post(name: Notification.Name(rawValue: "dismissModal"), object: nil)
// }
}
}
}
}
Present modal view on navigation to another view in swiftui
There is a view modifier in SwiftUI known as .onAppear(perform:)
, which is the SwiftUI counterpart to UIKit's viewDidAppear
and gives you an entry point upon the construction and display of a SwiftUI view. Simply add this modifier to View B (the view inside the sheet that you are presenting). In the closure that you provide to the modifier, you can change the state to present the picker as needed.
If you'd like the picker view to animate in after the view appears, the appropriate place to declare the transition and animation context is on the view acting as your picker view.
struct ViewB: View {
@State private var displayPicker = false
var body: some View {
VStack {
Text("This is View B")
if displayPicker {
PickerView()
.transition(.slide)
.animation(.easeInOut, value: displayPicker)
}
}
.onAppear {
displayPicker = true
}
}
}
Read more about the modifier here:
https://developer.apple.com/documentation/SwiftUI/AnyView/onAppear(perform:)
Present a new view when a condition has been met in SwiftUI
You can use the modifier .fullScreenCover
& you just need to pass a binding to a @State var
which you set to true when you want to display the modal.
example
struct ExampleScreenView: View {
@State var showModal: Bool = false
var body: some View {
VStack {
Text("Some Text")
.padding()
Button {
showModal = true
} label: {
Text("Show other view")
}
}
.fullScreenCover(isPresented: $showModal) {
VStack {
Color.white
Text("Some other text")
.padding()
Button {
showModal = false
} label: {
Text("close view")
}
}
}
}
}
This example the first view has a button that sets the bool to true, and shows the modal, the modal view has a button that sets the bool to false and closes the view.
The button is just for the sake of an example, but you can use any logic to set the bool. to true, and then you can present whatever view you choose within the fullScreenCover.
Specific for the login scenario, you can use a .onReceive
modifier to listen for a notification sent from your login successful code.
.onReceive(NotificationCenter.default.publisher(for: Notification.Name(rawValue: "didLogin"))
&
NotificationCenter.post(name:Notification.Name("didLogin"), object: nil)
Go to a new view using SwiftUI
The key is to use a NavigationView and a NavigationLink:
import SwiftUI
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
Text("Hello World")
NavigationLink(destination: DetailView()) {
Text("Do Something")
}
}
}
}
}
How to Push View or Present View Modally in SwiftUI dynamically?
A possible solution is to create a custom enum with available presentation types:
enum PresentationType {
case push, sheet // ...
}
and create a custom binding for activating different views:
func showChildView(presentationType: PresentationType) -> Binding<Bool> {
.init(
get: { self.showChildView && self.presentationType == presentationType },
set: { self.showChildView = $0 }
)
}
Full code:
struct ContentView: View {
@State var presentationType = PresentationType.push
@State var showChildView = false
func showChildView(as presentationType: PresentationType) -> Binding<Bool> {
.init(
get: { self.showChildView && self.presentationType == presentationType },
set: { self.showChildView = $0 }
)
}
var body: some View {
NavigationView {
VStack {
Button(action: {
self.presentationType = .push
self.showChildView = true
}) {
Text("Present new view as Push")
}
Button(action: {
self.presentationType = .sheet
self.showChildView = true
}) {
Text("Present new view as Sheet")
}
}
.navigationBarTitle("Main view", displayMode: .inline)
.background(
NavigationLink(
destination: ChildView(),
isActive: self.showChildView(presentationType: .push),
label: {}
)
)
}
.sheet(isPresented: self.showChildView(presentationType: .sheet)) {
ChildView()
}
}
}
struct ChildView: View {
var body: some View {
ZStack {
Color.red
Text("Child view")
}
}
}
Trying to move to a new view in swiftUI after a button press
to make the "move work", add this to "AddAssignment":
struct AddAssignment: View {
@State var toAssignment: Int? = nil
replace your Button("Create New Task", action: {...}, with
NavigationLink(destination: ViewAssignment(), tag: 1, selection: $toAssignment) {
Button("Create New Task") {
let task: [String] = [taskName, dueDate, subject, weighting, totalMarks]
print(task)
self.toAssignment = 1
}
}
make sure you wrap the whole thing in "NavigationView { ...}"
Show a new View from Button press Swift UI
For simple example you can use something like below
import SwiftUI
struct ExampleFlag : View {
@State var flag = true
var body: some View {
ZStack {
if flag {
ExampleView().tapAction {
self.flag.toggle()
}
} else {
OtherExampleView().tapAction {
self.flag.toggle()
}
}
}
}
}
struct ExampleView: View {
var body: some View {
Text("some text")
}
}
struct OtherExampleView: View {
var body: some View {
Text("other text")
}
}
but if you want to present more view this way looks nasty
You can use stack to control view state without NavigationView
For Example:
class NavigationStack: BindableObject {
let didChange = PassthroughSubject<Void, Never>()
var list: [AuthState] = []
public func push(state: AuthState) {
list.append(state)
didChange.send()
}
public func pop() {
list.removeLast()
didChange.send()
}
}
enum AuthState {
case mainScreenState
case userNameScreen
case logginScreen
case emailScreen
case passwordScreen
}
struct NavigationRoot : View {
@EnvironmentObject var state: NavigationStack
@State private var aligment = Alignment.leading
fileprivate func CurrentView() -> some View {
switch state.list.last {
case .mainScreenState:
return AnyView(GalleryState())
case .none:
return AnyView(LoginScreen().environmentObject(state))
default:
return AnyView(AuthenticationView().environmentObject(state))
}
}
var body: some View {
GeometryReader { geometry in
self.CurrentView()
.background(Image("background")
.animation(.fluidSpring())
.edgesIgnoringSafeArea(.all)
.frame(width: geometry.size.width, height: geometry.size.height,
alignment: self.aligment))
.edgesIgnoringSafeArea(.all)
.onAppear {
withAnimation() {
switch self.state.list.last {
case .none:
self.aligment = Alignment.leading
case .passwordScreen:
self.aligment = Alignment.trailing
default:
self.aligment = Alignment.center
}
}
}
}
.background(Color.black)
}
}
struct ExampleOfAddingNewView: View {
@EnvironmentObject var state: NavigationStack
var body: some View {
VStack {
Button(action:{ self.state.push(state: .emailScreen) }){
Text("Tap me")
}
}
}
}
struct ExampleOfRemovingView: View {
@EnvironmentObject var state: NavigationStack
var body: some View {
VStack {
Button(action:{ self.state.pop() }){
Text("Tap me")
}
}
}
}
In my opinion this bad way, but navigation in SwiftUI much worse
SwiftUI: Go to a new view from inside a modal
I understood your question in 2 different ways, and luckily I have both solutions.
If you want the following flow: ViewA -> Opens ViewB As modal -> opens ViewC as NavigatedView in ViewB
Then all you need to change is your ModalView
to this
struct ModalView: View {
@Binding var showModal: Bool
var body: some View {
NavigationView {
VStack (spacing: 30){
NavigationLink(destination: NewView()) {
Text("Take me to NewView")
}
Text("My Modal View")
.font(.title)
.padding()
Button("Close modal") {
self.showModal.toggle()
}
Button("Close modal and go to a new view") {
}
}
}
}
}
IF however what you mean is ViewA -> opens ViewsB as Moda -> ViewB then tells ViewA to navigate to ViewC
then please refer to this link, someone asked this question earlier and I provided the solution
SwiftUI transition from modal sheet to regular view with Navigation Link
Related Topics
iOS Enterprise Provisioning Profile Expiration
Change App Language in iOS Without Restarting the App
App Crashing When Using Firebase Auth, Reason: 'Default App Has Already Been Configured.'
Dragging Scnnode in Arkit Using Scenekit
Alphabetical Sections in Table Table View in Swift
Endless Scrolling Background in Spritekit
How to Detect an iOS App Installed or Upgraded
Get Average Color of Uiimage in Swift
How to Pass Swift Enum with @Objc Tag
How to Properly Set Uirequireddevicecapabilities
Uidatepicker Bug? Uicontroleventvaluechanged After Hitting Minimum Internal
Cannot Show Automatic Strong Passwords for App Bundleid
Invalid Redeclaration in Auto Code Generate Nsmanagedobject Subclass Swift 3
Objective-C Check If Subviews of Rotated Uiviews Intersect
Opening Testflight App from Another App and Deep Link to Specific App
Does Nsthread Create Autoreleasepool Automatically Now