I'm trying to write a custom ViewModifier
where my implementation needs to detect if the content
it is modifying is visible or not. This is not an ordinary ViewModifier
where it's irrelevant if the content is visible; the modifier is attempting to track visibility for the purpose of determining if the underlying content should be streamed via video capture.
(It's still confusing to me why Apple did not provide a .visible(_ visibility: Visibility)
with enum Visibility { case visible, case hidden, case collapsed }
, and instead encouraged using .opacity(_:)
to conditionally hide views. But that's another story.)
In any case, while I can set the opacity with .opacity(_:)
, I can't get the content
s opacity. Note that onAppear
is called, even for views with opacity set to 0.
struct MyViewModifier: ViewModifier {
func body(content: Content) -> some View {
content
.mymodifierimplemtation()
.onAppear() {
// Called even if content opacity is 0
print("Appeared")
}
}
}
Hopefully this makes sense. Any assistance appreciated.
You can create a custom modifier to set the view's opacity to 0 and use EnvironmentValues
to track the visibility of this view in your ViewModifier
using:
@Environment(\.visibility) var visibility
Environment Key:
struct VisibilityEnvironmentKey: EnvironmentKey {
static let defaultValue = Visibility.automatic
}
extension EnvironmentValues {
var visibility: Visibility {
get {
self[VisibilityEnvironmentKey.self]
}
set {
self[VisibilityEnvironmentKey.self] = newValue
}
}
}
Visibility Modifier:
extension View {
@ViewBuilder func visible(_ visibility: Visibility) -> some View {
Group {
if visibility != .automatic {
self
.opacity(visibility == .hidden ? 0: 1)
}
}.environment(\.visibility, visibility)
}
}