<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>AnyView &#8211; Wade Tregaskis</title>
	<atom:link href="https://wadetregaskis.com/tags/anyview/feed/" rel="self" type="application/rss+xml" />
	<link>https://wadetregaskis.com</link>
	<description></description>
	<lastBuildDate>Sat, 17 Feb 2024 16:51:39 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://wadetregaskis.com/wp-content/uploads/2016/03/Stitch-512x512-1-256x256.png</url>
	<title>AnyView &#8211; Wade Tregaskis</title>
	<link>https://wadetregaskis.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">226351702</site>	<item>
		<title>Hiding SwiftUI views</title>
		<link>https://wadetregaskis.com/hiding-swiftui-views/</link>
					<comments>https://wadetregaskis.com/hiding-swiftui-views/#comments</comments>
		
		<dc:creator><![CDATA[]]></dc:creator>
		<pubDate>Thu, 15 Feb 2024 01:42:38 +0000</pubDate>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Howto]]></category>
		<category><![CDATA[AnyView]]></category>
		<category><![CDATA[EmptyView]]></category>
		<category><![CDATA[Swift]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://wadetregaskis.com/?p=7711</guid>

					<description><![CDATA[There are several ways to hide a SwiftUI view, although they don&#8217;t all agree on what it means to hide the view. Do you want it to be invisible, or actually not there? To make it invisible you need only set its opacity to zero or use the hidden modifier. But the view will still&#8230; <a class="read-more-link" href="https://wadetregaskis.com/hiding-swiftui-views/" data-wpel-link="internal">Read more</a>]]></description>
										<content:encoded><![CDATA[
<p>There are several ways to hide a SwiftUI view, although they don&#8217;t all agree on what it <em>means</em> to hide the view.  Do you want it to be invisible, or actually not there?</p>



<p>To make it invisible you need only set its <a href="https://developer.apple.com/documentation/swiftui/view/opacity(_:)" data-wpel-link="external" target="_blank" rel="external noopener">opacity</a> to zero or use the <code><a href="https://developer.apple.com/documentation/swiftui/view/hidden()" data-wpel-link="external" target="_blank" rel="external noopener">hidden</a></code> modifier.  But the view will still be laid out just the same, and take up space in the GUI.</p>



<p>If you want to <em>actually</em> hide the view, so that it disappears completely, you can either not emit the view at all (e.g. conditionalise its existence with <code>if</code> or <code>switch</code>) or you can replace it with <code><a href="https://developer.apple.com/documentation/swiftui/emptyview/" data-wpel-link="external" target="_blank" rel="external noopener">EmptyView</a></code>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img fetchpriority="high" decoding="async" width="654" height="545" src="https://wadetregaskis.com/wp-content/uploads/2024/02/Wolf-amongst-the-sheep.avif" alt="" class="wp-image-7715" srcset="https://wadetregaskis.com/wp-content/uploads/2024/02/Wolf-amongst-the-sheep.avif 654w, https://wadetregaskis.com/wp-content/uploads/2024/02/Wolf-amongst-the-sheep-256x213.avif 256w, https://wadetregaskis.com/wp-content/uploads/2024/02/Wolf-amongst-the-sheep@2x.avif 1308w, https://wadetregaskis.com/wp-content/uploads/2024/02/Wolf-amongst-the-sheep-256x213@2x.avif 512w" sizes="(max-width: 654px) 100vw, 654px" /></figure>
</div>


<p><code>EmptyView</code> is pretty marvellous in this respect.  Notice how even though it&#8217;s a real view &#8211; an actual value that you emit from a view builder &#8211; layout collections (e.g. <code>HStack</code>) don&#8217;t &#8220;see&#8221; it &#8211; there&#8217;s no visible gap, from doubling up on the cell padding, like there would be if they simply treated <code>EmptyView</code>s like 0 wide ⨉ 0 high views.</p>



<p>You might ask, when would you actually <em>need</em> EmptyView?  Wouldn&#8217;t you&#8217;d just use conditional code to hide a view, e.g.:</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="" style="font-size:.875rem;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #0000FF">struct</span><span style="color: #000000"> </span><span style="color: #267F99">MyView</span><span style="color: #000000">: View {</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #0000FF">let</span><span style="color: #000000"> model: Model?</span></span>
<span class="line"><span style="color: #000000">    </span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #0000FF">var</span><span style="color: #000000"> body: some View {</span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">if</span><span style="color: #000000"> </span><span style="color: #0000FF">let</span><span style="color: #000000"> model {</span></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #795E26">Text</span><span style="color: #000000">(model.</span><span style="color: #001080">text</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">        }</span></span>
<span class="line"><span style="color: #000000">    }</span></span>
<span class="line"><span style="color: #000000">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #008000">// Now you can just use MyView(model: someOptional),</span></span>
<span class="line"><span style="color: #008000">// without having to unwrap it before every use.</span></span></code></pre></div>



<p>The above is making use of the &#8220;ViewBuilder mode&#8221;, to implicitly yield zero or more views which are automagically aggregated into a <code><a href="https://developer.apple.com/documentation/swiftui/tupleview" data-wpel-link="external" target="_blank" rel="external noopener">TupleView</a></code> (if you emit more than one), an optional view (if you dynamically emit zero or one), etc.  That&#8217;s very convenient, in simple cases like that.</p>



<p>But, &#8220;ViewBuilder mode&#8221; comes with a <em>lot</em> of limitations, including:</p>



<ul class="wp-block-list">
<li>Compiler diagnostics are far inferior to regular Swift code.</li>



<li>You cannot return early (i.e. use <code>return</code> statements) except by throwing an exception, which is not always semantically appropriate.</li>



<li>You cannot have nested functions.</li>



<li>You sometimes cannot use full Swift control flow syntax (e.g. switch statements).</li>
</ul>



<p>Fortunately, you can opt out of &#8220;ViewBuilder mode&#8221; by simply using an explicit <code>return</code> statement, but then you have to follow the usual rules for opaque return types, i.e. that the value be of the same type for every <code>return</code> statement.  You can use <code>AnyView</code> in concert with <code>EmptyView</code> to straighten the compiler&#8217;s knickers regarding the return type<sup data-fn="d83a6861-4b9d-4634-a63e-e5247eff8def" class="fn"><a href="#d83a6861-4b9d-4634-a63e-e5247eff8def" id="d83a6861-4b9d-4634-a63e-e5247eff8def-link">1</a></sup>, e.g.:</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="" style="font-size:.875rem;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #0000FF">struct</span><span style="color: #000000"> </span><span style="color: #267F99">MyView</span><span style="color: #000000">: View {</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #0000FF">let</span><span style="color: #000000"> model: Model?</span></span>
<span class="line"><span style="color: #000000">    </span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #0000FF">var</span><span style="color: #000000"> body: some View {</span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">guard</span><span style="color: #000000"> </span><span style="color: #0000FF">let</span><span style="color: #000000"> model </span><span style="color: #AF00DB">else</span><span style="color: #000000"> {</span></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #AF00DB">return</span><span style="color: #000000"> </span><span style="color: #795E26">AnyView</span><span style="color: #000000">(</span><span style="color: #795E26">EmptyView</span><span style="color: #000000">())</span></span>
<span class="line"><span style="color: #000000">        }</span></span>
<span class="line"><span style="color: #000000">        </span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">return</span><span style="color: #000000"> </span><span style="color: #795E26">AnyView</span><span style="color: #000000">(&lt;actual view contents&gt;)</span></span>
<span class="line"><span style="color: #000000">    }</span></span>
<span class="line"><span style="color: #000000">}</span></span></code></pre></div>



<p>…or &#8211; if you don&#8217;t mind the return type being <code>Optional</code>, which SwiftUI itself doesn&#8217;t &#8211; you can use a partially opaque return type:</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="" style="font-size:.875rem;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #0000FF">struct</span><span style="color: #000000"> </span><span style="color: #267F99">MyView</span><span style="color: #000000">: View {</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #0000FF">let</span><span style="color: #000000"> model: Model?</span></span>
<span class="line"><span style="color: #000000">    </span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #0000FF">var</span><span style="color: #000000"> body: </span><span style="color: #267F99">Optional</span><span style="color: #000000">&lt;some View&gt; {</span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">guard</span><span style="color: #000000"> </span><span style="color: #0000FF">let</span><span style="color: #000000"> model </span><span style="color: #AF00DB">else</span><span style="color: #000000"> {</span></span>
<span class="line"><span style="color: #000000">            </span><span style="color: #AF00DB">return</span><span style="color: #000000"> Body.</span><span style="color: #001080">none</span></span>
<span class="line"><span style="color: #000000">        }</span></span>
<span class="line"><span style="color: #000000">        </span></span>
<span class="line"><span style="color: #000000">        </span><span style="color: #AF00DB">return</span><span style="color: #000000"> &lt;actual view contents&gt;</span></span>
<span class="line"><span style="color: #000000">    }</span></span>
<span class="line"><span style="color: #000000">}</span></span></code></pre></div>



<p>Thanks to <a href="https://forums.swift.org/u/dmt/summary" data-wpel-link="external" target="_blank" rel="external noopener">Dima Galimzianov</a> for <a href="https://forums.swift.org/t/cannot-use-nil-or-none-with-optional-some-t/70098/2" data-wpel-link="external" target="_blank" rel="external noopener">helping me figure out how to do that</a>.</p>



<p>Note that in the trivial cases shown above there&#8217;s no <em>particularly</em> compelling reason to use these forms instead of the &#8220;ViewBuilder mode&#8221;, but you could hopefully imagine how, as the conditional logic gets more complicated, it becomes increasingly impractical to avoid using guard, or early returns otherwise.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<p>Note that while <code>AnyView</code> has a lot of FUD<sup data-fn="41306d14-0450-4ed5-a469-b2a06045dc54" class="fn"><a href="#41306d14-0450-4ed5-a469-b2a06045dc54" id="41306d14-0450-4ed5-a469-b2a06045dc54-link">2</a></sup> associated with it, as far as I can tell there&#8217;s really nothing wrong with it.  Most often it&#8217;s claimed to cause performance problems, but I&#8217;ve never detected that in my use, nor seen anyone provide a real example case of such.  And multiple people have gone looking for performance problems with <code>AnyView</code> and found nothing.  e.g. <a href="https://www.linkedin.com/in/nalexn/" data-wpel-link="external" target="_blank" rel="external noopener">Alexey Naumov</a>&#8216;s <a href="https://nalexn.github.io/anyview-vs-group/" data-wpel-link="external" target="_blank" rel="external noopener">Performance Battle: AnyView vs Group</a>.</p>
</div></div>



<p>In case you&#8217;re wondering, there&#8217;s no difference in show/hide behaviour either &#8211; it just works!</p>



<figure class="wp-block-video aligncenter fix-wolf-video-size"><video height="1086" style="aspect-ratio: 1304 / 1086;" width="1304" autoplay loop preload="auto" src="https://wadetregaskis.com/wp-content/uploads/2024/02/The-Big-Wolfie-Reveal.mp4" playsinline></video></figure>



<p>It&#8217;s possible that there&#8217;s some situations in which using <code>EmptyView</code> might cause animation issues, by confusing SwiftUI as to what the relationship is between view hierarchies over time, but I haven&#8217;t found that to be the case in practice.  And if it ever does crop up, you can always just explicitly <a href="https://developer.apple.com/documentation/swiftui/view/id(_:)" data-wpel-link="external" target="_blank" rel="external noopener">id</a> your views.</p>



<p><code>EmptyView</code> is one of those little sleeper features that seems irrelevant until you stumble upon a need for it, and then it&#8217;s <em>really</em> nice to have.</p>


<ol class="wp-block-footnotes"><li id="d83a6861-4b9d-4634-a63e-e5247eff8def">There&#8217;s technically another option: use a concrete return type instead.  But, that&#8217;s usually impractical &#8211; SwiftUI uses opaque return types <em>a lot</em>, such as for virtually all view modifiers, which force you to use opaque return types in turn.  And even when <em>that</em> isn&#8217;t an issue, good luck deducing the correct fully-qualified type name even for something as simple as a <code>LabeledContent</code>. <a href="#d83a6861-4b9d-4634-a63e-e5247eff8def-link" aria-label="Jump to footnote reference 1">↩︎</a></li><li id="41306d14-0450-4ed5-a469-b2a06045dc54">Literally, &#8220;Fear, Uncertainty, and Doubt&#8221;.  Used here in that face-value sense, not to suggest any malice on anyone&#8217;s part. <a href="#41306d14-0450-4ed5-a469-b2a06045dc54-link" aria-label="Jump to footnote reference 2">↩︎</a></li></ol>]]></content:encoded>
					
					<wfw:commentRss>https://wadetregaskis.com/hiding-swiftui-views/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		<enclosure url="https://wadetregaskis.com/wp-content/uploads/2024/02/The-Big-Wolfie-Reveal.mp4" length="186396" type="video/mp4" />

			<media:content url="https://wadetregaskis.com/wp-content/uploads/2024/02/Wolf-amongst-the-sheep.avif" medium="image" />
<post-id xmlns="com-wordpress:feed-additions:1">7711</post-id>	</item>
	</channel>
</rss>
