I'm trying to make an app using Apple's SwiftUI and I need to have two buttons that present two different views in a single List
row.
I use Xcode beta 7 and MacOS Catalina beta 7. I've tried to add a Button
that present the view but, I couldn't click it and when I tried on a simple Button
outside the List
and clicked it, the AddList()
view didn't appear. I've also tried adding a navigationButton
inside navigationButton
but it didn't work too. Adding a tapAction
doesn't work too when you click on it, the view still does not appear
NavigationView {
List(0..<5) { item in
NavigationLink(destination: ContentOfList()) {
Text("hello") // dummy text
Spacer()
Text("edit")
.tapAction {
AddList() // This is the view I want to present
}
}
}.navigationBarItems(trailing: NavigationLink(destination: AddList(), label: { // doesn't work within navigationBarItems
Image(systemName: "plus.circle.fill")
}))
}
I expect the AddList()
view to appear but in the two cases, it doesn't.
Much improved version (SwiftUI, iOS 13 beta 7)
The same solution works for dismissing Modals presented with the .sheet modifier.
import SwiftUI
struct DetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Button(
"Here is Detail View. Tap to go back.",
action: { self.presentationMode.wrappedValue.dismiss() }
)
}
}
struct RootView: View {
var body: some View {
VStack {
NavigationLink(destination: DetailView())
{ Text("I am Root. Tap for Detail View.") }
}
}
}
struct ContentView: View {
var body: some View {
NavigationView {
RootView()
}
}
}
Update: The NavigationButton was very short lived. In beta3 it is already deprecated. I am updating the code to use its replacement: NavigationLink.
You can present a view from all three places. Here's how:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
TopView().navigationBarTitle(Text("Top View"))
}
}
}
struct TopView: View {
@State private var viewTypeA = true
let detailViewA = DynamicNavigationDestinationLink(id: \String.self) { data in
ListA(passedData: data)
}
let detailViewB = DynamicNavigationDestinationLink(id: \String.self) { data in
ListB(passedData: data)
}
var body: some View {
List(0..<5) { item in
NavigationLink(destination: ListC(passedData: "FROM ROW #\(item)")) {
HStack {
Text("Row #\(item)")
Spacer()
Text("edit")
.tapAction {
self.detailViewA.presentedData?.value = "FROM TAP ACTION Row #\(item)"
}
}
}
}.navigationBarItems(trailing: Button(action: {
self.detailViewB.presentedData?.value = "FROM PLUS CIRCLE"
}, label: {
Image(systemName: "plus.circle.fill")
}))
}
}
struct ListA: View {
let passedData: String
var body: some View {
VStack {
Text("VIEW A")
Text(passedData)
}
}
}
struct ListB: View {
let passedData: String
var body: some View {
VStack {
Text("VIEW B")
Text(passedData)
}
}
}
struct ListC: View {
let passedData: String
var body: some View {
VStack {
Text("VIEW C")
Text(passedData)
}
}
}
improved version. (Swift, iOS 13 beta 4)
class NavigationModel : BindableObject {
var willChange = PassthroughSubject<Void, Never>()
var presentedData: String? {
didSet {
willChange.send()
}
}
func dismiss() { if presentedData != nil {
presentedData = nil
} }
}
struct ContentView: View {
var body: some View {
NavigationView {
MasterView()
}.environmentObject(NavigationModel())
}
}
struct MasterView: View {
@EnvironmentObject
var navigationModel: NavigationModel
var destinationLink = DynamicNavigationDestinationLink<String, String, DetailView>(id: \.self) { data in DetailView(data: data) }
var body: some View {
List(0..<10) { index in
Button("I am root. Tap for more details of #\(index).") {
self.navigationModel.presentedData = "#\(index)"
}
}
.navigationBarTitle("Master")
.onReceive(navigationModel.willChange) {
self.destinationLink.presentedData?.value = self.navigationModel.presentedData
}
}
}
struct DetailView: View {
@EnvironmentObject
var model: NavigationModel
let data: String
var body: some View {
Button("Here are details of \(data). Tap to go back.") {
self.model.dismiss()
}
.navigationBarTitle("Detail \(data)")
}
}
struct Empty : Hashable {
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif