Last active
January 1, 2025 02:45
-
-
Save dasdom/82a151394df3cc7ba21ca9328344c17c to your computer and use it in GitHub Desktop.
SwiftUI identity problem
Here is another simple version where the overlay content is provided by the calling leaf view (could also be easily adjusted to move the detail content selection to the presenter, same idea):
import SwiftUI
extension Optional {
var isSet: Bool {
set { if !newValue { self = .none } }
get {
switch self {
case .some(_): true
case .none: false
}
}
}
}
@Observable @MainActor
final class Presenter {
var presentedView : AnyView?
func showCover<V: View>(@ViewBuilder content: () -> V) {
presentedView = AnyView(content())
}
}
struct ContentView: View {
@State var presenter = Presenter()
var body: some View {
GeometryReader { proxy in
ZStack {
let landscape = proxy.size.height <= proxy.size.width
landscape ? Color.gray : Color.pink
SwitchingView(landscape: landscape)
}
.environment(presenter)
.fullScreenCover(isPresented: $presenter.presentedView.isSet) {
presenter.presentedView
}
}
}
}
struct SwitchingView: View {
let landscape : Bool
var body: some View {
HStack {
SelectionView(landscape: landscape)
DetailsView(landscape: landscape)
}
}
}
struct DetailsView: View {
var landscape: Bool
var body: some View {
VStack {
DetailInfoView()
if !landscape { UserView(landscape: landscape) }
}
}
}
struct SelectionView: View {
var landscape: Bool
var body: some View {
VStack {
if landscape { UserView(landscape: landscape) }
CategoriesView()
}
}
}
struct CategoriesView: View {
let listOfCategories = ["A", "list", "of", "categories"]
var body: some View {
List(listOfCategories, id:\.self) { item in
Text(item)
}
}
}
struct DetailInfoView: View {
let listOfInfo = ["Details", "about", "the", "selected", "info", "category"]
var body: some View {
List(listOfInfo, id:\.self) { item in
Text(item)
}
}
}
struct UserView: View {
var landscape: Bool
var body: some View {
(landscape ? AnyLayout(HStackLayout()) : AnyLayout(VStackLayout())) {
AvatarImageView()
ActionsView()
}
}
}
struct ActionsView: View {
var body: some View {
Text("View with actions for users")
}
}
struct AvatarImageView: View {
@Environment(Presenter.self) var presenter
var body: some View {
Button("Show detail") {
presenter.showCover {
Text("Detail Provided View")
}
}
}
}
#Preview {
ContentView()
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A few more best practices: Regardless of the particular issue, it is often a good idea not to change identity, if possible. E.g. the switching between
HStack
andVStack
can be done using this in an identity preserving ways:Also instead of such:
do this: