Please review Apple's article Choosing the right way to hide a view.
Contrary to what many other answers here suggest, Apple's article states that a conditional is the correct solution.
The exception is when you want to preserve an empty space where the hidden view used to be. In that case, using .opacity(0)
is the correct solution.
.hidden()
is only suggested if the visibility of the view is always off. I suspect that's equivalent to .opacity(0)
, perhaps simply being a clearer expression of intent for exactly the same solution under the hood.
If you do want a modifier to make it convenient to do this, I would offer the following tweak on other people's work:
extension View {
/// Hide or show a view based on a boolean value.
///
/// Example for hiding while reclaiming space:
///
/// Text("Label")
/// .isHidden(true)
///
/// Example for hiding, but leaving a gap where the hidden item was:
///
/// Text("Label")
/// .isHidden(true, remove: false)
///
/// - Parameters:
/// - hidden: whether to hide the view.
/// - remove: whether you want to reclaim the space taken by the hidden view.
@ViewBuilder func isHidden(_ hidden: Bool, remove: Bool = true) -> some View {
if remove {
if !hidden {
self
}
} else {
self.opacity(hidden ? 0 : 1)
}
}
}
Arranging the conditional that way has the advantage that, at least in the case where remove
is set to false, the structural identity of the hidden view is consistent through animation of the hidden
parameter.
On the other hand, if remove
is set to true, there is no view in the hidden case, so it's not possible to maintain structural identity. So if you are animating the hidden
parameter and remove
is true, you might run into some unpleasant animation (depending on where SwiftUI determines is the best guess for the geometry of the removed view). To solve that, the answer, in theory, is to use .matchedGeometryEffect
(see this to explore this technique). But I have found matchedGeometryEffect to be buggy, so for now, I would recommend that you turn animation off, and avoid all these headaches.