Reputation: 644
I have 3 views that are completely separate. I furthermore, do not want the ultraThinMaterial to add on as views stack over each other.
When View 2 appears over view 1 from the bottom edge, it should get removed from the bottom edge as well.
When I tried, either only a simple opacity animation runs or the view behind gets transitioned through the bottom edge as well..
Basically aiming for ZStack of views like how the iOS default navigation works or how the sheet in Apple Maps get overlaid on top of each other.
enum ViewToShow: Identifiable {
var id: ViewToShow {
return self
}
case view1
case view2
case view3
}
@Observable
class SheetStackModel {
var viewsItemManagedByThisSheet: [ViewToShow] = []
init() {
pushIntoStack(view: .view1)
}
func getLastView() -> ViewToShow? {
return viewsItemManagedByThisSheet.last
}
func pushIntoStack(view: ViewToShow) {
withAnimation(.default.speed(1.8)) {
viewsItemManagedByThisSheet.append(view)
}
}
func popOutOfStack() {
withAnimation(.default.speed(1.8)) {
_ = viewsItemManagedByThisSheet.removeLast()
}
}
}
struct View1: View {
@Environment(SheetStackModel.self) var sheetStackModel
var body: some View {
GeometryReader { localGeo in
VStack {
Text("View 1")
Button(action: {
sheetStackModel.pushIntoStack(view: .view2)
}, label: {
Text("Go to View 2")
})
}
}
}
}
struct View2: View {
@Environment(SheetStackModel.self) var sheetStackModel
var body: some View {
GeometryReader { localGeo in
VStack {
Text("View 2")
Button(action: {
sheetStackModel.popOutOfStack()
}, label: {
Text("Go back to View 1")
})
Button("Go to Detail 3") {
sheetStackModel.pushIntoStack(view: .view3)
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.ultraThinMaterial)
}
}
struct DetailView3: View {
@Environment(SheetStackModel.self) var sheetStackModel
var body: some View {
VStack {
Text("Even more detail View")
Button("go back to view 2") {
sheetStackModel.popOutOfStack()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.ultraThinMaterial)
}
}
struct ContentView: View {
var body: some View {
ZStack {
if let lastView = sheetStackModel.getLastView() {
switch lastView {
case .view1:
View1()
case .view2:
View2()
case .view3:
DetailView3()
}
}
}
.transition(.asymmetric(insertion: .move(edge: .bottom), removal: .move(edge: .bottom)))
}
}
Upvotes: 0
Views: 284
Reputation: 21740
I would suggest the following changes:
ZStack
.GeometryReader
, this is not needed for the animation..frame(maxWidth: .infinity, maxHeight: .infinity)
to the individual views, so that they fill the screen..ultraThinMaterial
to be seen on each layer then apply it to the ZStack
instead.Like this:
struct View1: View {
@Environment(SheetStackModel.self) var sheetStackModel
var body: some View {
// No GeometryReader needed
VStack {
// content as before
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // <- ADDED
}
}
struct View2: View {
@Environment(SheetStackModel.self) var sheetStackModel
var body: some View {
// No GeometryReader needed
VStack {
// content as before
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
// .ultraThinMaterial background removed
}
}
struct DetailView3: View {
@Environment(SheetStackModel.self) var sheetStackModel
var body: some View {
VStack {
// content as before
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
// .ultraThinMaterial background removed
}
}
struct ContentView: View {
@Environment(SheetStackModel.self) var sheetStackModel // <- ADDED
var body: some View {
ZStack {
if let lastView = sheetStackModel.getLastView() {
switch lastView {
// transitions added to separate views
case .view1:
View1()
.transition(.move(edge: .bottom))
case .view2:
View2()
.transition(.move(edge: .bottom))
case .view3:
DetailView3()
.transition(.move(edge: .bottom))
}
}
}
.background(.ultraThinMaterial) // <- Moved to here
}
}
Hope this gets you closer to the effect you are trying to achieve.
Upvotes: 0