<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[iOS DevX by Xavier]]></title><description><![CDATA[Welcome to iOS DevX by Xavier.
Here I post Swift &amp; SwiftUI tutorial with demonstrations and tips. Subscribe to my newsletter to get daily updates via email.]]></description><link>https://xavier7t.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 10 Sep 2026 22:40:29 GMT</lastBuildDate><atom:link href="https://xavier7t.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Custom iOS 26 Full Page Swipe-Back Gesture]]></title><description><![CDATA[The code in this post is available here.
Introduction
iOS 26 introduced a revolutionary swipe-to-go-back feature that allows users to navigate back from any white space area on the screen, not just fr]]></description><link>https://xavier7t.com/custom-ios-26-full-page-swipe-back-gesture</link><guid isPermaLink="true">https://xavier7t.com/custom-ios-26-full-page-swipe-back-gesture</guid><category><![CDATA[iOS]]></category><category><![CDATA[UIkit]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[iOS26]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sat, 16 May 2026 20:41:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/63e18119181298b6f65b595f/bd14c62a-2bc5-4d83-8b30-7c7714a8426c.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The code in this post is available <a href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202605-May%202026/FullPageSwipeToGoBack/DemoFullPageSwipeBackGesture-20260516.swift"><strong>here</strong></a>.</p>
<h2>Introduction</h2>
<p>iOS 26 introduced a revolutionary swipe-to-go-back feature that allows users to navigate back from any white space area on the screen, not just from the edges. This gesture enhances user experience by making navigation more intuitive and fluid. However, this article will guide you through implementing a custom version of this behavior for your own applications.</p>
<h2>Motivation: Why Implement Custom Swipe-Back?</h2>
<p>There are two compelling reasons to implement custom swipe-back gestures in your iOS apps:</p>
<ol>
<li><p><strong>Limited iOS 26 Support</strong>: The native iOS 26 swipe-to-go-back feature only works when navigation links use the default back button. If you customize the back button—for example, replacing it with a toolbar item like an SF Symbol "xmark" close button—the swipe gesture may not function as expected.</p>
</li>
<li><p><strong>Backward Compatibility</strong>: Supporting this behavior on older iOS versions ensures your app remains accessible and user-friendly across all supported devices, not just those running the latest OS version.</p>
</li>
</ol>
<h2>Step-by-Step Implementation</h2>
<p>The following implementation provides a reusable view modifier that enables full-screen swipe-back gestures on navigation controllers:</p>
<h3>Step 0: Create example/caller screen to observe difference beweten native behavior and unsupported use cage</h3>
<pre><code class="language-swift">    struct ContentView: View {
        @State private var showingDetail = false
        
        var body: some View {
            NavigationStack {
                List {
                    NavigationLink(destination: DetailView()) {
                        Text("Default Behavior")
                    }
                    
                    NavigationLink(destination: AnotherDetailView()) {
                        Text("Custom Behavior")
                    }
                }
//                .enableSwipeBackGesture()  // We'll be building this modifier
            }
        }
    }

    struct DetailView: View {
        var body: some View {
            VStack(spacing: 20) {
                Text("Detail Content")
                    .font(.title2)
                
                Button("Close") {
                    // Custom close action
                }
                .buttonStyle(.bordered)
            }
            .navigationTitle("Detail")
        }
    }

    struct AnotherDetailView: View {
        @Environment(\.dismiss) var dismiss
        var body: some View {
            Text("Another Detail View")
                .navigationTitle("Another")
                .navigationBarBackButtonHidden()
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        Button {
                            dismiss()
                        } label: {
                            Label("Close", systemImage: "xmark")
                                .labelStyle(.iconOnly)
                        }

                    }
                }
        }
    }
</code></pre>
<p>This screen contains two navigation links. First one is default behavior, where users can navigate back to parent view from destination by swiping back from any blank space area. Second doesn't support this bahavior because of custom tool bar item.</p>
<h3>Step 1: Create the ViewController Class</h3>
<pre><code class="language-swift">final class ViewController: UIViewController, UIGestureRecognizerDelegate {
    private var fullScreenSwipeBackGesture: UIPanGestureRecognizer?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        enableSwipeBackIfNeeded()
    }

    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
        enableSwipeBackIfNeeded()
    }

    func enableSwipeBackIfNeeded() {
        guard let navigationController else {
            return
        }
        navigationController.interactivePopGestureRecognizer?.isEnabled = true
        navigationController.interactivePopGestureRecognizer?.delegate = nil

        installFullScreenSwipeBackGesture(on: navigationController)
    }
}
</code></pre>
<h3>Step 2: Install the Full-Screen Gesture Recognizer</h3>
<pre><code class="language-swift">private func installFullScreenSwipeBackGesture(on navigationController: UINavigationController) {
    guard fullScreenSwipeBackGesture == nil else {
        return
    }

    guard
        let gestureRecognizer = navigationController.interactivePopGestureRecognizer,
        let targets = gestureRecognizer.value(forKey: "targets") as? [NSObject],
        let target = targets.first?.value(forKey: "target")
    else {
        return
    }

    let panGestureRecognizer = UIPanGestureRecognizer(
        target: target,
        action: NSSelectorFromString("handleNavigationTransition:")
    )
    panGestureRecognizer.maximumNumberOfTouches = 1
    panGestureRecognizer.delegate = self
    panGestureRecognizer.name = "FullScreenSwipeBack"
    navigationController.view.addGestureRecognizer(panGestureRecognizer)
    fullScreenSwipeBackGesture = panGestureRecognizer
}
</code></pre>
<h3>Step 3: Implement Gesture Filtering Logic</h3>
<pre><code class="language-swift">func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -&gt; Bool {
    guard let navigationController, navigationController.viewControllers.count &gt; 1 else {
        return false
    }

    guard let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else {
        return false
    }

    let translation = panGestureRecognizer.translation(in: gestureRecognizer.view)
    return translation.x &gt; 0 &amp;&amp; abs(translation.x) &gt; abs(translation.y)
}
</code></pre>
<h3>Step 4: Create the UIViewControllerRepresentable Wrapper</h3>
<pre><code class="language-swift">private struct SwipeBackGestureEnabler: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -&gt; ViewController {
        ViewController()
    }

    func updateUIViewController(_ uiViewController: ViewController, context: Context) {
        uiViewController.enableSwipeBackIfNeeded()
    }
}
</code></pre>
<h3>Step 5: Add the View Modifier Extension</h3>
<pre><code class="language-swift">extension View {
    func enableSwipeBackGesture() -&gt; some View {
        background(SwipeBackGestureEnabler())
    }
}
</code></pre>
<h2>Example Usage</h2>
<p>Here's how to integrate this modifier into your SwiftUI app:</p>
<pre><code class="language-swift">struct ContentView: View {
    @State private var showingDetail = false
    
    var body: some View {
        NavigationStack {
            List {
                NavigationLink(destination: DetailView()) {
                    Text("Default Behavior")
                }
                
                NavigationLink(destination: AnotherDetailView()) {
                    Text("Custom Behavior")
                }
            }
            .enableSwipeBackGesture()  // Uncommented this line 
        }
    }
}
</code></pre>
<h2>Key Components Explained:</h2>
<ol>
<li><p><code>UIViewControllerRepresentable</code>: This protocol bridges SwiftUI views with UIKit view controllers, allowing us to manage the lifecycle of our custom <code>ViewController</code>.</p>
</li>
<li><p><code>UIGestureRecognizerDelegate</code>: By conforming to this protocol, we gain control over gesture recognition behavior through the <code>gestureRecognizerShouldBegin(_:)</code> method.</p>
</li>
<li><p><strong>Gesture Filtering Logic</strong>: The implementation ensures that swipe gestures only trigger when:</p>
<ul>
<li><p>There are multiple view controllers in the navigation stack (preventing accidental dismissals on root views)</p>
</li>
<li><p>The horizontal translation exceeds vertical translation (ensuring it's a swipe, not a tap or scroll)</p>
</li>
</ul>
</li>
<li><p><strong>Full-Screen Coverage</strong>: Unlike edge-based swipes, this implementation captures gestures anywhere on the screen by adding the gesture recognizer to the navigation controller's view.</p>
</li>
</ol>
<h2>Benefits of This Implementation</h2>
<ul>
<li><p><strong>Customizable Back Button</strong>: You can now use custom toolbar items (like SF Symbols) while maintaining swipe-back functionality</p>
</li>
<li><p><strong>Consistent UX</strong>: Users experience the same intuitive navigation pattern regardless of how you configure your navigation UI</p>
</li>
<li><p><strong>Cross-Version Support</strong>: Works on iOS versions that don't have native full-screen swipe support built-in</p>
</li>
</ul>
<h2>Conclusion</h2>
<p>Implementing a custom swipe-back gesture gives you greater control over user navigation in your iOS applications. By using the <code>enableSwipeBackGesture()</code> view modifier, you can seamlessly integrate this feature while maintaining clean, declarative SwiftUI code. This approach ensures your app provides a modern, fluid navigation experience that works consistently across different configurations and iOS versions.</p>
<hr />
<p><em>If you found this article helpful, please consider supporting my work on</em> <a href="https://buymeacoffee.com/xavierios"><em>Buy Me a Coffee</em></a><em>. Don't forget to subscribe to my newsletter for more tutorials like this!</em></p>
]]></content:encoded></item><item><title><![CDATA[Liquid Glass Navigation Bar in SwiftUI]]></title><description><![CDATA[iOS 26 introduces new capabilities for customizing navigation bars in SwiftUI — including navigation subtitles, the ToolbarSpacer, and more powerful ToolbarItemGroup placement. In this tutorial, we’ll build a small demo that showcases how to use thes...]]></description><link>https://xavier7t.com/liquid-glass-navigation-bar-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/liquid-glass-navigation-bar-in-swiftui</guid><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iOS]]></category><category><![CDATA[iOS26]]></category><category><![CDATA[LiquidGlass ]]></category><category><![CDATA[iosdevx]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Mon, 28 Jul 2025 04:09:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753675711538/30d50ec2-9501-4502-9a3f-dc17caaf3cd6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>iOS 26 introduces new capabilities for customizing navigation bars in SwiftUI — including <strong>navigation subtitles</strong>, the <code>ToolbarSpacer</code>, and more powerful <code>ToolbarItemGroup</code> placement. In this tutorial, we’ll build a small demo that showcases how to use these features.</p>
<p>PS: The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202507-Jul%202025/DemoNavBar20250727.swift"><strong>here</strong></a>.</p>
<h1 id="heading-step-1-set-up-a-navigation-view-with-a-list">🧱 Step 1: Set up a navigation view with a list</h1>
<p>Use <code>NavigationView</code> to gain access to the new iOS 26 toolbar system.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">if</span> #available(iOS <span class="hljs-number">26</span>, *) {
    <span class="hljs-type">NavigationView</span> {
        <span class="hljs-type">List</span> {
            <span class="hljs-type">LinearGradient</span>(colors: [.blue, .green], startPoint: .leading, endPoint: .trailing)
                .listRowInsets(.<span class="hljs-keyword">init</span>())

            <span class="hljs-type">Toggle</span>(<span class="hljs-string">"Enables Toolbar Spacer"</span>, isOn: $isToolbarSpacerEnabled)

            <span class="hljs-type">Text</span>(<span class="hljs-string">"Item 1"</span>)
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Item 2"</span>)
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Item 3"</span>)
        }
    }
}
</code></pre>
<p>Using <code>#available(iOS 26, *)</code> ensures that the new APIs don’t cause crashes on older OS versions.</p>
<p>The linear gradient is just for demo purpose to make the glass effect more visible.</p>
<h1 id="heading-step-2-set-the-navigation-title-and-subtitle">🔤 Step 2: Set the Navigation Title and Subtitle</h1>
<p>New in iOS 26 is the <code>.navigationSubtitle(_:)</code> modifier. This lets you add a small subtitle under the main title.</p>
<pre><code class="lang-swift">.navigationTitle(<span class="hljs-type">Text</span>(<span class="hljs-string">"Favorites"</span>))
.navigationSubtitle(<span class="hljs-string">"Synced just now"</span>)
</code></pre>
<p>See the subtitle below the regular nav title? As always, when your scroll up, both titles in large display mode will become inline automatically.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753674958887/e1409174-5205-4f40-ae80-9f838c40342a.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753674994221/4e1a2937-c39a-4894-922b-415ccd04b4f6.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-step-3-add-toolbar-items-with-apis-before-ios-26">🧰 Step 3: Add Toolbar Items (with APIs before iOS 26)</h1>
<p>We now define toolbar items, for example with three buttons.</p>
<pre><code class="lang-swift">.toolbar {
        <span class="hljs-type">ToolbarItem</span>(placement: .topBarTrailing) {
            <span class="hljs-type">Button</span>(<span class="hljs-string">"Add"</span>, systemImage: <span class="hljs-string">"plus"</span>) { }
        }
        <span class="hljs-type">ToolbarItem</span>(placement: .topBarTrailing) {
            <span class="hljs-type">Button</span>(<span class="hljs-string">"Download"</span>, systemImage: <span class="hljs-string">"square.and.arrow.down"</span>) { }
        }
        <span class="hljs-type">ToolbarItem</span>(placement: .topBarTrailing) {
            <span class="hljs-type">Button</span>(<span class="hljs-string">"Share"</span>, systemImage: <span class="hljs-string">"square.and.arrow.up"</span>) { }
        }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753675142837/8b963198-4a8f-40e9-8388-59cabfad2922.png" alt class="image--center mx-auto" /></p>
<p>See in iOS 26, the new design grouped all three toolbar items together. Also, inline navtile title and subtile got pushed to the leading side if trailing items took much space.</p>
<h1 id="heading-step-4-new-api-toolbarspacer-and-toolbargroup">🔸 Step 4: New API <code>ToolbarSpacer</code> and <code>ToolbarGroup</code></h1>
<p>iOS 26 introduces <code>ToolbarSpacer</code>, which gives you fine-grained control over toolbar layout. Let’s replace the toolbar content with the code below.</p>
<pre><code class="lang-swift"><span class="hljs-type">ToolbarItemGroup</span>(placement: .topBarTrailing) {
    <span class="hljs-type">Button</span>(<span class="hljs-string">"Add"</span>, systemImage: <span class="hljs-string">"plus"</span>) { }
    <span class="hljs-type">Button</span>(<span class="hljs-string">"Download"</span>, systemImage: <span class="hljs-string">"square.and.arrow.down"</span>) { }
}
<span class="hljs-type">ToolbarSpacer</span>(placement: .topBarTrailing)
<span class="hljs-type">ToolbarItemGroup</span>(placement: .topBarTrailing) {
    <span class="hljs-type">Button</span>(<span class="hljs-string">"Share"</span>, systemImage: <span class="hljs-string">"square.and.arrow.up"</span>) { }
}
</code></pre>
<p>Using <code>ToolbarItemGroup</code> allows us to group buttons together, while <code>ToolbarSpacer</code> inserts spacing between them to seperate different type of functionalities.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753675391754/a7630e84-a5ce-489a-8f84-8e6530452912.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-summary">✅ Summary</h2>
<p>With iOS 26, SwiftUI gives us:</p>
<ul>
<li><p><code>navigationSubtitle(_:)</code> for better context in navigation bars</p>
</li>
<li><p><code>ToolbarItemGroup</code> to logically group actions</p>
</li>
<li><p><code>ToolbarSpacer</code> to space groups apart visually and functionally</p>
</li>
</ul>
<p>These additions make it easier to design adaptive, organized toolbars that better reflect user intent.</p>
<p>This lets you separate logical sections of toolbar items — improving both UX and layout responsiveness.</p>
<p>Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email. If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Liquid Glass Tab View in SwiftUI]]></title><description><![CDATA[Hi iOS devs, it’s been a long while since last time! Here I’m back with some cool stuff about iOS 26~
iOS 26 brings a refined aesthetic to TabView—with a native liquid glass effect and powerful new APIs like .tabViewBottomAccessory. In this tutorial,...]]></description><link>https://xavier7t.com/liquid-glass-tab-view-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/liquid-glass-tab-view-in-swiftui</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[Swift]]></category><category><![CDATA[iOS]]></category><category><![CDATA[iOS26]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[Liquid Glass]]></category><category><![CDATA[tabview]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Fri, 25 Jul 2025 23:50:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753487175223/9cffec1f-194f-4cf2-b01a-b92480ea0f61.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi iOS devs, it’s been a long while since last time! Here I’m back with some cool stuff about iOS 26~</p>
<p>iOS 26 brings a refined aesthetic to <code>TabView</code>—with a native <strong>liquid glass effect</strong> and powerful new APIs like <code>.tabViewBottomAccessory</code>. In this tutorial, we’ll walk through building a <strong>searchable, tinted</strong> <code>TabView</code> with a floating bottom action, which the fancy liquid glass effect.</p>
<p>Let’s get started! 🚀 PS: The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202507-Jul%202025/DemoTabView20250735.swift"><strong>here</strong></a>.</p>
<h3 id="heading-step-1-create-a-placeholder-list-view">Step 1: Create a Placeholder List View</h3>
<p>This simple list helps demonstrate the colorful aesthetics behind the liquid glass. You can swap this with real data later.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> placeholderList: some <span class="hljs-type">View</span> {
    <span class="hljs-type">List</span> {
        <span class="hljs-type">ForEach</span>(<span class="hljs-type">Array</span>(<span class="hljs-number">0</span>...<span class="hljs-number">10</span>), id: \.<span class="hljs-keyword">self</span>) { index <span class="hljs-keyword">in</span>
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Row \(index)"</span>)
                .foregroundStyle(.black)
                .bold()
                .padding(.vertical)
                .listRowBackground(
                    <span class="hljs-type">Color</span>(hue: <span class="hljs-type">CGFloat</span>(index) / <span class="hljs-number">10</span>, saturation: <span class="hljs-number">0.55</span>, brightness: <span class="hljs-number">0.9</span>)
                )
        }
    }
}
</code></pre>
<p>💡 <em>Each row gets a unique hue, helping you visualize transparency and layering effects.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753486239925/8ca35e10-b933-4e5c-94c9-612ea2a1c6dc.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-step-2-build-the-tabview-with-search-and-navigation">Step 2: Build the <code>TabView</code> with Search and Navigation</h3>
<p>The <code>Tab</code> API introduced in iOS 18 (and enhanced in iOS 26) lets you customize each tab with SF Symbols and roles. In iOS 26, Tab with <code>search</code> role (SwiftUI alternative of <code>UISearchTab</code> in UIKit), got a new look.</p>
<pre><code class="lang-swift"><span class="hljs-meta">@available</span>(iOS <span class="hljs-number">18</span>, *)
<span class="hljs-keyword">var</span> tabView: some <span class="hljs-type">View</span> {
    <span class="hljs-type">TabView</span> {
        <span class="hljs-type">Tab</span>(<span class="hljs-string">"Search"</span>, systemImage: <span class="hljs-string">"magnifyingglass"</span>, role: .search) {
            <span class="hljs-type">NavigationStack</span> {
                placeholderList
                    .searchable(text: $searchText, prompt: <span class="hljs-string">"Looking for something?"</span>)
                    .navigationTitle(<span class="hljs-string">"Search"</span>)
            }
        }
        <span class="hljs-type">Tab</span>(<span class="hljs-string">"Home"</span>, systemImage: <span class="hljs-string">"house"</span>) {
            <span class="hljs-type">NavigationStack</span> {
                placeholderList
                    .navigationTitle(<span class="hljs-string">"Home"</span>)
            }
        }
        <span class="hljs-type">Tab</span>(<span class="hljs-string">"Settings"</span>, systemImage: <span class="hljs-string">"gear"</span>) {
            <span class="hljs-type">NavigationStack</span> {
                placeholderList
                    .navigationTitle(<span class="hljs-string">"Settings"</span>)
            }
        }
    }
    .tint(.teal) <span class="hljs-comment">// adjust this color based on your use case</span>
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753488079596/3816e61a-2d12-4e0e-981d-99c2c81c1f98.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753488089798/f1da5909-d58e-4239-b3e4-d50daa7cfab9.png" alt class="image--center mx-auto" /></p>
<p>Note that the order/position of tab with search role matters. If it’s the first tab in tab view, search tab will show with search bar expanded by default. Otherwise others tabs will show and users have to tap on the magnifying glass icon to expand the search bar.</p>
<h3 id="heading-step-3-add-the-liquid-glass-bottom-accessory">Step 3: Add the Liquid Glass Bottom Accessory</h3>
<p>In iOS 26, <code>TabView</code> supports <code>.tabViewBottomAccessory</code>, perfect for floating call-to-action buttons.</p>
<pre><code class="lang-swift">@<span class="hljs-type">ViewBuilder</span>
<span class="hljs-keyword">var</span> mainView: some <span class="hljs-type">View</span> {
    <span class="hljs-keyword">if</span> #available(iOS <span class="hljs-number">26.0</span>, *) {
        tabView
            .tabViewBottomAccessory {
                <span class="hljs-type">Button</span> {
                    <span class="hljs-comment">// Your action goes here</span>
                } label: {
                    <span class="hljs-type">HStack</span> {
                        <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"plus"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"Add a new record now"</span>)
                    }
                }
                .bold()
                .tint(.primary)
            }
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> #available(iOS <span class="hljs-number">18</span>, *) {
        tabView <span class="hljs-comment">// Fallback for older versions</span>
    }
}
</code></pre>
<p>🧪 <em>This button floats above the</em> <code>TabView</code> like a piece of interactive glass.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753488107780/400b3fda-2cf3-4a27-b75f-75542965ab95.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-final-thoughts">✅ Final Thoughts</h3>
<p>This is how you can build a <strong>modern, beautiful TabView experience</strong> in iOS 26 with SwiftUI. You now have:</p>
<ul>
<li><p>A <strong>searchable list</strong></p>
</li>
<li><p>A <strong>three-tab interface</strong> using the modern <code>Tab</code> API</p>
</li>
<li><p>A <strong>floating bottom accessory</strong></p>
</li>
<li><p>Liquid glass effect and dynamic coloring baked in</p>
</li>
</ul>
<hr />
<h3 id="heading-bonus-tip-clean-design-matters">🧼 Bonus Tip: Clean Design Matters</h3>
<ul>
<li><p>Use <code>.tint(_:)</code> consistently for accent color theming.</p>
</li>
<li><p>Keep your <code>NavigationStack</code>s lightweight.</p>
</li>
<li><p>Use <code>#available</code> checks to maintain backward compatibility.</p>
</li>
</ul>
<p>Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email. If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Create Radial Pattern in SwiftUI]]></title><description><![CDATA[How to Create a Radial Pattern in SwiftUI
In this tutorial, we'll explore how to create a vibrant radial pattern using SwiftUI. We'll use gradients and circles to form a stunning geometric design. If you’re looking to add visually appealing elements ...]]></description><link>https://xavier7t.com/create-radial-pattern-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/create-radial-pattern-in-swiftui</guid><category><![CDATA[SwiftUI]]></category><category><![CDATA[Swift]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[app development]]></category><category><![CDATA[Design]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sun, 15 Sep 2024 04:29:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726374127029/7335e804-9184-4a91-9754-07b4916e48a6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-how-to-create-a-radial-pattern-in-swiftui">How to Create a Radial Pattern in SwiftUI</h1>
<p>In this tutorial, we'll explore how to create a vibrant radial pattern using SwiftUI. We'll use gradients and circles to form a stunning geometric design. If you’re looking to add visually appealing elements to your apps, this radial pattern is a great way to start. PS: The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202409-Sep%202024/DemoRadialPattern20240914.swift"><strong>here</strong></a>.</p>
<h2 id="heading-final-result">Final Result</h2>
<p>We'll build a radial pattern of colored dots that rotate around a central point, masked by a colorful linear gradient, making it stand out beautifully.</p>
<h2 id="heading-step-1-defining-the-dots-view">Step 1: Defining the Dots View</h2>
<p>The <code>Dots</code> view is responsible for arranging dots evenly around the center of the pattern.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Dots</span>: <span class="hljs-title">View</span> </span>{
            <span class="hljs-keyword">let</span> <span class="hljs-built_in">count</span>: <span class="hljs-type">Int</span>
            <span class="hljs-keyword">let</span> dotSize: <span class="hljs-type">CGFloat</span>
            <span class="hljs-keyword">let</span> xOffset: <span class="hljs-type">CGFloat</span>

            <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
                <span class="hljs-type">ZStack</span> {
                    <span class="hljs-type">ForEach</span>(<span class="hljs-number">0</span>..&lt;<span class="hljs-built_in">count</span>, id: \.<span class="hljs-keyword">self</span>) {
                        dot.rotationEffect(.degrees(<span class="hljs-type">Double</span>($<span class="hljs-number">0</span> * <span class="hljs-number">365</span> / <span class="hljs-built_in">count</span>)))
                    }
                }
            }

            <span class="hljs-keyword">var</span> dot: some <span class="hljs-type">View</span> {
                <span class="hljs-type">Group</span> {
                    <span class="hljs-type">Circle</span>()
                        .frame(width: dotSize, height: dotSize)
                        .hidden()
                    <span class="hljs-type">Circle</span>()
                        .frame(width: dotSize, height: dotSize)
                        .offset(x: xOffset)
                }
            }
        }
</code></pre>
<h3 id="heading-breakdown">Breakdown:</h3>
<ul>
<li><p><code>count</code>: Number of dots in the ring.</p>
</li>
<li><p><code>dotSize</code>: Size of each individual dot.</p>
</li>
<li><p><code>xOffset</code>: The horizontal distance of each dot from the center of the view.</p>
</li>
<li><p><code>ForEach</code>: We use this to repeat the dots around the circle.</p>
</li>
<li><p><code>rotationEffect</code>: This evenly spaces the dots around the center by rotating them based on their index in the <code>ForEach</code> loop.</p>
</li>
<li><p><code>offset</code>: This moves the dots horizontally, positioning them along the radius of the circle.</p>
</li>
</ul>
<p>Long story short, <code>Dots</code> view is used to present a group circles in a circle. Below is a preview of <code>DotsView</code> with a count of 8.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726374295907/c851ab02-a951-454b-a7ae-165683ab8032.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-step-2-creating-the-radial-pattern">Step 2: Creating the Radial Pattern</h2>
<p>Next, we’ll define the <code>RadialPattern</code> view. It will consist of multiple circles (dots) arranged in concentric rings (by using <code>Dots</code> view defined above).</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">RadialPattern</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> size: <span class="hljs-type">CGFloat</span> = <span class="hljs-number">250</span>
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">ZStack</span> {
                <span class="hljs-type">Circle</span>()
                    .fill(<span class="hljs-type">Color</span>.clear)
                <span class="hljs-type">Dots</span>(<span class="hljs-built_in">count</span>: <span class="hljs-number">20</span>, dotSize: size / <span class="hljs-number">10</span>, xOffset: size / <span class="hljs-number">2</span>)
                <span class="hljs-type">Dots</span>(<span class="hljs-built_in">count</span>: <span class="hljs-number">20</span>, dotSize: size / <span class="hljs-number">15</span>, xOffset: size / <span class="hljs-number">2.4</span>)
                    .rotationEffect(.degrees(<span class="hljs-number">25</span>))
                <span class="hljs-type">Dots</span>(<span class="hljs-built_in">count</span>: <span class="hljs-number">20</span>, dotSize: size / <span class="hljs-number">20</span>, xOffset: size / <span class="hljs-number">2.9</span>)
                <span class="hljs-type">Dots</span>(<span class="hljs-built_in">count</span>: <span class="hljs-number">20</span>, dotSize: size / <span class="hljs-number">15</span>, xOffset: size / <span class="hljs-number">1.7</span>)
                    .rotationEffect(.degrees(<span class="hljs-number">25</span>))
                <span class="hljs-type">Dots</span>(<span class="hljs-built_in">count</span>: <span class="hljs-number">20</span>, dotSize: size / <span class="hljs-number">20</span>, xOffset: size / <span class="hljs-number">1.6</span>)
            }
        }
    }
</code></pre>
<h3 id="heading-breakdown-1">Breakdown:</h3>
<ul>
<li><p><code>ZStack</code>: This stacks all the circles and dots on top of each other.</p>
</li>
<li><p><code>Circle()</code>: A base circle filled with <code>Color.clear</code> (invisible) is used as a center point for our pattern.</p>
</li>
<li><p><code>Dots</code>: This is a custom view we defined above, which will handle the arrangement of dots. We call this view multiple times to create concentric rings with different offsets and sizes.</p>
</li>
<li><p><code>rotationEffect</code>: This rotates the dots slightly, adding a subtle rotation for each ring to create a dynamic design.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726374371168/234ab701-c724-4ef4-81df-9a4244f62a25.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-step-3-applying-a-linear-gradient">Step 3: Applying a Linear Gradient</h2>
<p>We’ll start by adding a <code>LinearGradient</code> as the background of our view. This will be masked by the radial pattern later, creating a colorful effect.</p>
<p>Here’s the code for the gradient:</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">LinearGradient</span>(colors: [
                .red, .orange, .yellow, .green, .blue, .purple
            ], startPoint: .leading, endPoint: .trailing)
            .mask(<span class="hljs-type">RadialPattern</span>())
        }
    }
</code></pre>
<h3 id="heading-breakdown-2">Breakdown:</h3>
<ul>
<li><p><code>LinearGradient</code>: A gradient transitioning between red, orange, yellow, green, blue, and purple colors.</p>
</li>
<li><p>The gradient spans from the left (<code>.leading</code>) to the right (<code>.trailing</code>) of the screen.</p>
</li>
<li><p><code>mask(RadialPattern())</code>: This masks the gradient with our <code>RadialPattern</code>.</p>
</li>
</ul>
<p>Voila! And of course, you can change the look of this pattern by masking it on another view, like a solid color, radial gradient or image etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726374394909/157b4c95-ab28-4840-b99c-12d4c0806b2b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>By masking a colorful gradient with a radial pattern of dots, you can create stunning and dynamic designs in SwiftUI. This technique can be extended further by experimenting with different shapes, colors, or even animating the pattern.</p>
<p>Feel free to play around with the parameters to make the design your own!</p>
<p>Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email. If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Custom Toggle (Switch) in SwiftUI]]></title><description><![CDATA[Hi there, long time no see! Today I’m going to demonstrate how to create a custom toggle in SwiftUI from scratch.
With a custom toggle, you have the freedom to imbue your interface with a distinctive personality that aligns perfectly with your brand ...]]></description><link>https://xavier7t.com/custom-toggle-switch-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/custom-toggle-switch-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[toggle]]></category><category><![CDATA[iosdevx]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Fri, 29 Dec 2023 17:36:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703871283574/eca739bf-19ad-43c3-82db-6f4127b437fc.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hi there, long time no see! Today I’m going to demonstrate how to create a custom toggle in SwiftUI from scratch.</p>
<p>With a custom toggle, you have the freedom to imbue your interface with a distinctive personality that aligns perfectly with your brand or app theme. Beyond aesthetics, customization grants you precise control over the behavior and animations of the toggle, ensuring a seamless and engaging user experience.</p>
<p>Without further ado, let’s get started.</p>
<p>PS: The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202312-Dec%202023/DemoCustomToggle20231229.swift"><strong>here</strong></a>.</p>
<h1 id="heading-step-1-set-up-basic-toggle-view-skeleton-and-content-view-for-preview">Step 1: Set up basic toggle view skeleton and content view for preview</h1>
<ol>
<li><p>Create a ToggleView struct that conforms to View.</p>
</li>
<li><p>In side Toggle View’s body, create a HStack that contains a Text, a Spacer and a RoundedRectangle.</p>
</li>
<li><p>Add a <code>text</code> property that allows we pass a text to the toggle.</p>
</li>
<li><p>Make the corner radius for the rounded rectangle large to make the edges smoother. You can also replace it with a <code>Capsule</code> if you prefer.</p>
</li>
<li><p>Add a binding bool called <code>isOn</code>, which reads and writes a bool from outside.</p>
</li>
<li><p>Alter the foreground color of the rounded rectangle based on <code>isOn</code>, using an ternary operator <code>isOn ? onColor : offColor</code>. Ideally the color should be configurable, for this tutorial, we’ll keep it simple and use <code>.orange</code> and <code>.accentColor</code>.</p>
</li>
</ol>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ToggleView</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">let</span> text: <span class="hljs-type">LocalizedStringKey</span>
        @<span class="hljs-type">Binding</span> <span class="hljs-keyword">var</span> isOn: <span class="hljs-type">Bool</span>
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">HStack</span> {
                <span class="hljs-type">Text</span>(text)
                <span class="hljs-type">Spacer</span>()
                <span class="hljs-type">RoundedRectangle</span>(cornerRadius: <span class="hljs-number">50</span>)
                    .foregroundColor(isOn ? .orange : .accentColor)
                    .frame(width: <span class="hljs-number">51</span>, height: <span class="hljs-number">31</span>)
                    .onTapGesture { isOn.toggle() }
            }
        }
    }
</code></pre>
<p>In the content view, create two toggles and pass a constant true and false for the binding so that we can easily see how the view looks when toggle is on and off at the same time.</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">VStack</span> {
                <span class="hljs-type">ToggleView</span>(text: <span class="hljs-string">"Custom Toggle On"</span>, isOn: .constant(<span class="hljs-literal">true</span>))
                <span class="hljs-type">ToggleView</span>(text: <span class="hljs-string">"Custom Toggle Off"</span>, isOn: .constant(<span class="hljs-literal">false</span>))
            }
            .padding()
        }
    }
</code></pre>
<p>Below is how it looks as of now. Next step is to add a circle to indicate the toggle state (on or off).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703869809826/929c790e-9361-47cf-9bdd-ae2188d2be6d.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-step-2-circle-overlay">Step 2 - Circle Overlay</h1>
<p>To show if the toggle is on or off, we need a circle (or another shape you prefer) a horizontal offset.</p>
<ol>
<li><p>Add a computed property that determines the offset based on <code>isOn</code>. i.e. <code>var circleOffset: CGFloat { isOn ? 11: -11 }</code></p>
</li>
<li><p>Add an overlay for the rounded rectangle. Inside the overlay, add a circle with x offset of the offset defined above.</p>
</li>
</ol>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ToggleView</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">let</span> text: <span class="hljs-type">LocalizedStringKey</span>
        @<span class="hljs-type">Binding</span> <span class="hljs-keyword">var</span> isOn: <span class="hljs-type">Bool</span>
        <span class="hljs-comment">// -------------- New in Step 2</span>
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> circleOffset: <span class="hljs-type">CGFloat</span> {
            isOn ? <span class="hljs-number">11</span> : -<span class="hljs-number">11</span>
        }
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">HStack</span> {
                <span class="hljs-type">Text</span>(text)
                <span class="hljs-type">Spacer</span>()
                <span class="hljs-type">RoundedRectangle</span>(cornerRadius: <span class="hljs-number">50</span>)
                    .foregroundColor(isOn ? .orange : .accentColor)
                    .frame(width: <span class="hljs-number">51</span>, height: <span class="hljs-number">31</span>)
                    <span class="hljs-comment">// -------------- New in Step 2</span>
                    .overlay(
                        <span class="hljs-type">Circle</span>()
                            .frame(width: <span class="hljs-number">25</span>,
                                   height: <span class="hljs-number">25</span>)
                            .foregroundColor(.white)
                            .padding(<span class="hljs-number">3</span>)
                            .offset(x: circleOffset)
                    )
            }
        }
    }
</code></pre>
<p>Now the circle will pushed to right hand side when toggle is on and left hand side if toggle is off.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703870236661/32f19efd-e79a-468c-8838-f5b8a3150eae.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-step-3-image-overlay-for-the-circle-optional">Step 3 - Image Overlay for the Circle (Optional)</h1>
<p>This step is optional. If you want, you can also provide a small icon as an overlay of the circle. This icon will definitely look better if its color is changing based on the toggle state.</p>
<p>Below is an example using "checkmark" and "xmark" SF symbol.</p>
<pre><code class="lang-swift"><span class="hljs-type">Circle</span>()
    .frame(width: <span class="hljs-number">25</span>,
           height: <span class="hljs-number">25</span>)
    .foregroundColor(.white)
    .padding(<span class="hljs-number">3</span>)
    <span class="hljs-comment">// -------------- New in Step 3</span>
    .overlay(
        <span class="hljs-type">Image</span>(systemName: isOn ? <span class="hljs-string">"checkmark"</span> : <span class="hljs-string">"xmark"</span>)
            .resizable()
            .aspectRatio(contentMode: .fit)
            .font(.title.weight(.bold))
            .frame(width: <span class="hljs-number">10</span>,
                   height: <span class="hljs-number">10</span>)
            .foregroundColor(isOn ? .orange : .accentColor)
    )
    .offset(x: circleOffset)
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703870501722/8b8e4d76-9105-444a-8a15-1b9304e26884.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-step-4-simple-but-important-logic">Step 4 - Simple but important logic</h1>
<p>As a toggle, don’t forget to change the binding bool value when it’s tapped.</p>
<p>So add an <code>onTapGesture</code> for the RoundedRectangle. To ensure smooth transition, we can also give it a faster animation.</p>
<pre><code class="lang-swift"><span class="hljs-type">RoundedRectangle</span>(cornerRadius: <span class="hljs-number">50</span>)
    .foregroundColor(isOn ? .orange : .accentColor)
    .frame(width: <span class="hljs-number">51</span>,
           height: <span class="hljs-number">31</span>)
    .overlay(
        <span class="hljs-type">Circle</span>()
            .frame(width: <span class="hljs-number">25</span>,
                   height: <span class="hljs-number">25</span>)
            .foregroundColor(.white)
            .padding(<span class="hljs-number">3</span>)
            .overlay(
                <span class="hljs-type">Image</span>(systemName: isOn ? <span class="hljs-string">"checkmark"</span> : <span class="hljs-string">"xmark"</span>)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .font(.title.weight(.bold))
                    .frame(width: <span class="hljs-number">10</span>,
                           height: <span class="hljs-number">10</span>)
                    .foregroundColor(isOn ? .orange : .accentColor)
            )
            .offset(x: circleOffset)
    )
    <span class="hljs-comment">// -------------- New in Step 4</span>
    .animation(.linear(duration: <span class="hljs-number">0.15</span>), value: isOn)
    .onTapGesture { isOn.toggle() }
</code></pre>
<p>And that’s it! Our toggle is done.</p>
<p>One more thing, in this tutorial, we hardcoded the on and off colors, label as a text etc, actually these can all be a parameter so that the toggle is more customizable, and you can then pass a view as the label instead of a string/localized string key, or pass two colors for design the rounded rectangle color, or even the image/icon on the circle. But I believe this post can give you an idea of the basic customization.</p>
<p>That’s everything for this post.</p>
<p>Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email. If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a>.</p>
]]></content:encoded></item><item><title><![CDATA[Objective-C & SwiftUI Integration]]></title><description><![CDATA[Introduction
In the world of iOS app development, SwiftUI has gained significant popularity due to its modern, declarative approach to building user interfaces. However, there are times when you may need to leverage existing Objective-C view controll...]]></description><link>https://xavier7t.com/objective-c-swiftui-integration</link><guid isPermaLink="true">https://xavier7t.com/objective-c-swiftui-integration</guid><category><![CDATA[iOS]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[Objective C]]></category><category><![CDATA[UIkit]]></category><category><![CDATA[iosdevx]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sat, 01 Jul 2023 14:46:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688222762787/2db62d0a-dcc3-4228-b620-930a1d7eb9ee.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In the world of iOS app development, SwiftUI has gained significant popularity due to its modern, declarative approach to building user interfaces. However, there are times when you may need to leverage existing Objective-C view controllers in your SwiftUI project. Integrating Objective-C view controllers with SwiftUI allows you to tap into the vast ecosystem of Objective-C libraries, frameworks, and UI components while enjoying the benefits of SwiftUI's flexibility and simplicity. In this blog post, we will explore the seamless integration of Objective-C view controllers with SwiftUI, unlocking new possibilities for your app development endeavors.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202306-Jun%202023"><strong>here</strong></a>.</p>
<p>If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a></p>
<h1 id="heading-what-well-be-making">What We’ll be Making</h1>
<p>For demonstration purposes, we’re going to build a SwiftUI View which contains an Objective-C(OC) ViewController with a UILabel. And when we tap on the label, the label text switch between <code>"Hello, SwiftUI View!"</code> and <code>"Hello, Objective-C ViewController!"</code>. Without further talking, let’s get started!</p>
<h1 id="heading-step-1-create-an-oc-view-controller">Step 1. Create an OC View Controller</h1>
<p>Go to the project navigation and select a group where you’d like to save the OC view controller, right click and select <strong>New File…</strong>, then select <strong>Cocoa Touch Class</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688222559292/c9e31ad7-262b-4275-91b4-6c3e8a1312eb.png" alt class="image--center mx-auto" /></p>
<p>Tap <strong>Next</strong> and name the class as <code>OCViewController</code> and make sure it’s a subclass of <code>UIViewController</code> and the language is OC.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688222589650/a006116e-f868-4f59-a96a-3d67b2858920.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-step-2-create-a-bridging-header">Step 2 - Create a Bridging Header</h1>
<p>To use an OCView or OCViewController, the OC class should be exposed to Swift. Therefore, we need an OC bridging header that contains import expressions to expose the OC classes we need.</p>
<p>After Step 1, you should see an auto warning like below, select <strong>Create Bridging Header</strong>. If you canceled or selected <strong>Don’t Create</strong> accidentally, simply manually create a header file named as <code>ProjectName-Bridging-Header.h</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688222611742/838a084f-8803-4397-8d85-e82c87dea3b9.png" alt class="image--center mx-auto" /></p>
<p>Inside the header file, we just need an import expression to expose the class we need in Swift.</p>
<pre><code class="lang-objectivec"><span class="hljs-meta">#import <span class="hljs-meta-string">"OCViewController.h"</span></span>
</code></pre>
<p>If you’re using a different name for the OC class, remember to replace the header name with the class name of your choice.</p>
<h1 id="heading-step-3-define-the-uilabel">Step 3. Define the UILabel</h1>
<p>Since we need access of the UILabel in Swift, it should be defined as a property and exposed in the header of the view controller header.</p>
<p>So go to <code>OCViewController.h</code> and declare a property of type UILabel.</p>
<pre><code class="lang-objectivec"><span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">OCViewController</span> : <span class="hljs-title">UIViewController</span></span>
<span class="hljs-keyword">@property</span>(<span class="hljs-keyword">nonatomic</span>, <span class="hljs-keyword">strong</span>, <span class="hljs-keyword">readwrite</span>) <span class="hljs-built_in">UILabel</span> *label;
<span class="hljs-keyword">@end</span>
</code></pre>
<h1 id="heading-step-4-set-up-the-uilabel-in-the-view-controller">Step 4. Set up the UILabel in the View Controller</h1>
<p>Now go to <code>OCViewController.m</code> to configure the UILabel and add it to the root view inside <code>viewDidLoad</code> method of the <code>OCViewController</code>.</p>
<pre><code class="lang-objectivec"><span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">DemoObjectiveCIntegration20230630_OCViewController</span></span>

- (<span class="hljs-keyword">void</span>)viewDidLoad {
    [<span class="hljs-keyword">super</span> viewDidLoad];
    <span class="hljs-keyword">self</span>.view.backgroundColor = [<span class="hljs-built_in">UIColor</span> systemBackgroundColor];
    _label = [[<span class="hljs-built_in">UILabel</span> alloc] initWithFrame:<span class="hljs-built_in">CGRectMake</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">300</span>, <span class="hljs-number">50</span>)];
    _label.adjustsFontSizeToFitWidth = <span class="hljs-literal">YES</span>;
    _label.textColor = [<span class="hljs-built_in">UIColor</span> systemCyanColor];
    _label.textAlignment = <span class="hljs-built_in">NSTextAlignmentCenter</span>;
    _label.center = <span class="hljs-keyword">self</span>.view.center;
    [<span class="hljs-keyword">self</span>.view addSubview:_label];
}

<span class="hljs-keyword">@end</span>
</code></pre>
<p>The code above:</p>
<ul>
<li><p>Sets the background color of the view to the system background color using <code>[UIColor systemBackgroundColor]</code>.</p>
</li>
<li><p>Creates an instance of <code>UILabel</code> with a frame of <code>(0, 0, 300, 50)</code> and assigns it to the <code>**_label**</code> property defined in Step 3.</p>
</li>
<li><p>Sets the <code>adjustsFontSizeToFitWidth</code> property of <code>_label</code> to <code>YES</code>, which enables adjusting the font size to fit the width of the label.</p>
</li>
<li><p>Sets the text color of <code>_label</code> to the system cyan color using <code>[UIColor systemCyanColor]</code>.</p>
</li>
<li><p>Sets the text alignment of <code>_label</code> to center using <code>NSTextAlignmentCenter</code>.</p>
</li>
<li><p>Sets the center of <code>_label</code> to the center of the view using <a target="_blank" href="http://self.view.center"><code>self.view.center</code></a>.</p>
</li>
<li><p>Adds <code>_label</code> as a subview to the root view using <code>[self.view addSubview:_label]</code>.</p>
</li>
</ul>
<h1 id="heading-step-5-create-a-swiftui-view">Step 5 - Create a SwiftUI View</h1>
<p>Similar to Step 1, add a new file, but select <strong>SwiftUI View</strong> as the template. We’re going to replace the default text view <code>Text("Hello, World!")</code> with the OC view later.</p>
<pre><code class="lang-swift"><span class="hljs-comment">//MARK: - SwiftUI View</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"Hello, World!"</span>)
        }
    }
    <span class="hljs-comment">//MARK: - SwiftUI Preview</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView_Previews</span>: <span class="hljs-title">PreviewProvider</span> </span>{
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">var</span> previews: some <span class="hljs-type">View</span> {
            <span class="hljs-type">ContentView</span>()
        }
    }
</code></pre>
<h1 id="heading-step-6-create-a-uiviewcontrollerrepresentable-struct">Step 6 - Create a UIViewControllerRepresentable Struct</h1>
<p>To bring the OC view controller into SwiftUI view, we need to make a UIViewControllerRepresentable structure. This step is similar to integrating Swift UIKit to SwiftUI as demonstrated in the previous post <a target="_blank" href="https://xavier7t.com/integrating-uikit-into-swiftui">Integrating UIKit into SwiftUI</a>.</p>
<p>To do this, let’s create a struct called <code>OCView</code> and make it conform to the protocol <code>UIViewControllerRepresentable</code>. And this protocol contains two required methods - <code>makeUIViewController</code> and <code>updateUIViewController</code>.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">OCView</span>: <span class="hljs-title">UIViewControllerRepresentable</span> </span>{
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeUIViewController</span><span class="hljs-params">(context: Context)</span></span> -&gt; <span class="hljs-type">OCViewController</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-type">OCViewController</span>()
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateUIViewController</span><span class="hljs-params">(<span class="hljs-number">_</span> uiViewController: OCViewController, context: Context)</span></span> {
        }
    }
</code></pre>
<h1 id="heading-step-8-add-binding-logic">Step 8. Add Binding Logic</h1>
<p>To toggle the UILabel text, we need a binding bool in the <code>OCView</code> struct, and then in the <code>updateUIViewController</code>method, we can change the UILabel text.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">OCView</span>: <span class="hljs-title">UIViewControllerRepresentable</span> </span>{
        @<span class="hljs-type">Binding</span> <span class="hljs-keyword">var</span> showOC: <span class="hljs-type">Bool</span>
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeUIViewController</span><span class="hljs-params">(context: Context)</span></span> -&gt; <span class="hljs-type">OCViewController</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-type">OCViewController</span>()
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateUIViewController</span><span class="hljs-params">(<span class="hljs-number">_</span> uiViewController: OCViewController, context: Context)</span></span> {
            uiViewController.label.text = showOC ? <span class="hljs-string">"Hello, Objective-C ViewController!"</span> : <span class="hljs-string">"Hello, SwiftUI View!"</span>
        }
    }
</code></pre>
<p>Inside the <code>OCView</code> struct, add the <code>@Binding</code> bool property called <code>showOC</code>.</p>
<p>Then inside the <code>updateUIViewController</code> method, we can use a ternary operator to check the value of <code>showOC</code> and update the UILabel text value accordingly.</p>
<h1 id="heading-step-9-update-swiftui-view">Step 9. Update SwiftUI View</h1>
<p>And finally, we can bring the <code>OCView</code> to the SwiftUI View. And to toggle the UILabel text, let’s add a state boolean property called <code>showOC</code> with an initial value of <code>false</code>. Then an <code>onTapSture</code> view modifier to toggle <code>showOC</code> then the <code>OCView</code> is tapped.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
        @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> showOC: <span class="hljs-type">Bool</span> = <span class="hljs-literal">false</span>
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">OCView</span>(showOC: $showOC)
                .onTapGesture {
                    showOC.toggle()
                }
        }
    }
</code></pre>
<p>And that’s it! See how the integration works below:</p>
<h2 id="heading-initial-stage">Initial stage:</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688222647325/d729f152-5eec-4da9-ac21-b8055f415623.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-after-tapping">After tapping:</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688222662206/5a406457-1a94-4202-8d2a-d723a45095ed.png" alt class="image--center mx-auto" /></p>
<p>That’s all about OC integration with SwiftUI. In short, after definition of OC view controller and SwiftUI view, we need to make a representable struct for the OC view controller and use the struct inside SwiftUI whenever needed!</p>
<p>Again, If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a><strong>.</strong> Don’t forget to subscribe to my newsletter to get more posts like this via email updates!</p>
]]></content:encoded></item><item><title><![CDATA[Lazy Grid in SwiftUI]]></title><description><![CDATA[Hey everyone, happy WWDC 2023!
In today’s post, we’re going to take a look at LazyVGrid in SwiftUI and create a custom calendar view with it. As you can tell from the cover, this calendar view will display the weekdays in the title for each month and...]]></description><link>https://xavier7t.com/lazy-grid-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/lazy-grid-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[calendar]]></category><category><![CDATA[iosdevx]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Mon, 05 Jun 2023 12:47:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685969215103/e11f0074-2e3a-443e-9f1f-b1f8f06d5bc6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey everyone, happy WWDC 2023!</p>
<p>In today’s post, we’re going to take a look at <code>LazyVGrid</code> in SwiftUI and create a custom calendar view with it. As you can tell from the cover, this calendar view will display the weekdays in the title for each month and allow the user to navigate between months and there a button to switch back to today. Today will be highlighted with a crimson circle and the selected date will be highlighted with a skyblue circle. Apart from <code>LazyVGrid</code>, we’ll also create some functions that work with <code>Calendar</code> and <code>Date</code> classes.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202306-Jun%202023/DemoCustomCalendarView20230604.swift"><strong>here</strong></a>.</p>
<p>If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios"><strong>buymeacoffee.com/xavierios</strong></a></p>
<h3 id="heading-intro">Intro</h3>
<p>Creating a custom calendar view in SwiftUI can be a useful and practical addition to your app. While SwiftUI provides built-in components like <code>DatePicker</code> and <code>CalendarView</code>, they may not always meet your specific requirements in terms of functionality or design. By building a custom calendar view, you have complete control over the layout, styling, and interaction of the calendar, allowing you to tailor it to your app's unique needs.</p>
<p>A custom calendar view can be beneficial in various scenarios. For instance, you might want to display events or appointments for a specific date or allow users to select dates within a particular range. You may also want to highlight certain dates or provide additional features such as navigating between months or displaying weekdays in the title.</p>
<p>In this tutorial, we'll walk through the process of creating a custom calendar view in SwiftUI step-by-step. We'll cover essential concepts such as working with dates, using SwiftUI's layout system, handling user interactions, and more. By the end of this tutorial, you'll have a functional and customizable calendar view that you can integrate into your SwiftUI app.</p>
<p>So let's get started and build our own custom calendar view</p>
<h3 id="heading-step-1-create-a-new-swiftui-project"><strong>Step 1: Create a New SwiftUI Project</strong></h3>
<p>Open Xcode and create a new SwiftUI project. Name it "CustomCalendarView" or choose any name you prefer.</p>
<h3 id="heading-step-2-set-up-the-calendar-view"><strong>Step 2: Set Up the Calendar View</strong></h3>
<p>Replace the contents of the ContentView.swift file with the following code:</p>
<pre><code class="lang-swift">
<span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> month = <span class="hljs-number">1</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> year = <span class="hljs-number">1970</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDate = <span class="hljs-type">Date</span>()
    <span class="hljs-keyword">let</span> skyblue: <span class="hljs-type">Color</span> = .<span class="hljs-keyword">init</span>(red: <span class="hljs-number">118</span>/<span class="hljs-number">255</span>, green: <span class="hljs-number">169</span>/<span class="hljs-number">255</span>, blue: <span class="hljs-number">255</span>/<span class="hljs-number">255</span>)
    <span class="hljs-keyword">let</span> crimson: <span class="hljs-type">Color</span> = .<span class="hljs-keyword">init</span>(red: <span class="hljs-number">233</span>/<span class="hljs-number">255</span>, green: <span class="hljs-number">28</span>/<span class="hljs-number">255</span>, blue: <span class="hljs-number">76</span>/<span class="hljs-number">255</span>)
    <span class="hljs-keyword">let</span> calendar = <span class="hljs-type">Calendar</span>.current
    <span class="hljs-keyword">let</span> dateFormatter: <span class="hljs-type">DateFormatter</span> = {
        <span class="hljs-keyword">let</span> formatter = <span class="hljs-type">DateFormatter</span>()
        formatter.dateFormat = <span class="hljs-string">"d"</span>
        <span class="hljs-keyword">return</span> formatter
    }()

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-comment">// Calendar view code goes here</span>
    }
}
</code></pre>
<p>In this step, we set up the initial structure for our calendar view. We defined some state variables for the month, year, and selected date. Additionally, we declared color constants and created a date formatter to format the day numbers.</p>
<h3 id="heading-step-3-create-the-calendar-title-and-navigation-buttons"><strong>Step 3: Create the Calendar Title and Navigation Buttons</strong></h3>
<p>Inside the <code>body</code> property of the <code>ContentView</code> struct, add the following code:</p>
<pre><code class="lang-swift"><span class="hljs-type">VStack</span> {
    <span class="hljs-type">HStack</span> {
        <span class="hljs-comment">// Title</span>
        <span class="hljs-type">Spacer</span>()
        <span class="hljs-type">Text</span>(<span class="hljs-string">"\\(calendar.monthSymbols[month - 1]) \\(String(year))"</span>)
            .font(.title)
            .fontDesign(.monospaced)
        <span class="hljs-type">Spacer</span>()
        <span class="hljs-type">Button</span> {
            showToday()
        } label: {
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Today"</span>)
                .bold()
        }
    }
    <span class="hljs-comment">// Calendar content</span>
}
.padding()
</code></pre>
<p>In this step, we added a <code>VStack</code> to organize the calendar view. Inside the <code>VStack</code>, we created an <code>HStack</code> to display the calendar title. We used the <code>monthSymbols</code> property of the <code>Calendar</code> struct to get the month name based on the <code>month</code>variable. The <code>Today</code> button will call the <code>showToday()</code> function when tapped.</p>
<h3 id="heading-step-4-implement-calendar-navigation"><strong>Step 4: Implement Calendar Navigation</strong></h3>
<p>Below the <code>HStack</code>, add the following code to enable navigation between months:</p>
<pre><code class="lang-swift"><span class="hljs-type">HStack</span>(spacing: <span class="hljs-number">2</span>) {
    <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"chevron.backward.circle.fill"</span>)
        <span class="hljs-comment">// Previous month button</span>
    <span class="hljs-comment">// Calendar month view</span>
    <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"chevron.forward.circle.fill"</span>)
        <span class="hljs-comment">// Next month button</span>
}
.padding(.horizontal, <span class="hljs-number">20</span>)
</code></pre>
<p>In this step, we added two <code>Image</code> views to represent the previous and next month buttons. We'll implement their functionality in the upcoming steps.</p>
<h3 id="heading-step-5-create-the-calendar-month-view"><strong>Step 5: Create the Calendar Month View</strong></h3>
<p>Inside the <code>HStack</code> created in the previous step, add the following code to create the calendar month view:</p>
<pre><code class="lang-swift"><span class="hljs-type">LazyVGrid</span>(columns: <span class="hljs-type">Array</span>(repeating: <span class="hljs-type">GridItem</span>(), <span class="hljs-built_in">count</span>: <span class="hljs-number">7</span>), spacing: <span class="hljs-number">10</span>) {
    <span class="hljs-type">Group</span> {
        <span class="hljs-type">Text</span>(<span class="hljs-string">"SUN"</span>)
        <span class="hljs-type">Text</span>(<span class="hljs-string">"MON"</span>)
        <span class="hljs-type">Text</span>(<span class="hljs-string">"TUE"</span>)
        <span class="hljs-type">Text</span>(<span class="hljs-string">"WED"</span>)
        <span class="hljs-type">Text</span>(<span class="hljs-string">"THU"</span>)
        <span class="hljs-type">Text</span>(<span class="hljs-string">"FRI"</span>)
        <span class="hljs-type">Text</span>(<span class="hljs-string">"SAT"</span>)
    }
    .bold()
    .foregroundColor(.secondary)
    .fontDesign(.monospaced)

    <span class="hljs-type">ForEach</span>(getCalendarDays(), id: \\.<span class="hljs-keyword">self</span>) { date <span class="hljs-keyword">in</span>
        <span class="hljs-comment">// Calendar day cell</span>
    }
}
.frame(width: <span class="hljs-type">UIScreen</span>.main.bounds.width*<span class="hljs-number">0.8</span>)
</code></pre>
<p>In this step, we created a <code>LazyVGrid</code> to display the calendar days. The <code>Group</code> at the beginning contains the weekday labels (SUN, MON, TUE, etc.). We then use a <code>ForEach</code> loop to iterate through the <code>getCalendarDays()</code> function, which will return the dates for the current month. We will implement the functionality of the calendar day cell in the next step.</p>
<h3 id="heading-step-6-implement-calendar-day-cell"><strong>Step 6: Implement Calendar Day Cell</strong></h3>
<p>Inside the <code>ForEach</code> loop in the previous step, add the following code to create the calendar day cell:</p>
<pre><code class="lang-swift"><span class="hljs-type">ZStack</span> {
    <span class="hljs-comment">// Show crimson circle for today</span>
    <span class="hljs-comment">// Show sky blue circle for selected date</span>
    <span class="hljs-comment">// Show date number on the top</span>
    <span class="hljs-comment">// Transparent circle for padding</span>
}
.onTapGesture {
    <span class="hljs-comment">// Handle date selection</span>
}
</code></pre>
<p>In this step, we created a <code>ZStack</code> to stack different elements in the calendar day cell. We use <code>Circle</code> views to represent the selected date and today's date. The date number is displayed on top of the circles. Finally, we added an <code>onTapGesture</code>modifier to handle date selection.</p>
<h3 id="heading-step-7-implement-calendar-navigation-actions"><strong>Step 7: Implement Calendar Navigation Actions</strong></h3>
<p>Below the <code>LazyVGrid</code>, add the following code to implement the navigation actions:</p>
<pre><code class="lang-swift"><span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"chevron.backward.circle.fill"</span>)
    .resizable()
    .scaledToFit()
    .foregroundColor(.secondary)
    .frame(width: <span class="hljs-number">35</span>, height: <span class="hljs-number">35</span>)
    .onTapGesture {
        <span class="hljs-comment">// Navigate to previous month</span>
    }

<span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"chevron.forward.circle.fill"</span>)
    .resizable()
    .scaledToFit()
    .foregroundColor(.secondary)
    .frame(width: <span class="hljs-number">35</span>, height: <span class="hljs-number">35</span>)
    .onTapGesture {
        <span class="hljs-comment">// Navigate to next month</span>
    }
</code></pre>
<p>In this step, we added the previous and next month buttons. We used the SF Symbols system icon "<a target="_blank" href="http://chevron.backward.circle">chevron.backward.circle</a>.fill" and "<a target="_blank" href="http://chevron.forward.circle">chevron.forward.circle</a>.fill" to represent the buttons. We also implemented the <code>onTapGesture</code> modifiers to handle the navigation actions.</p>
<h3 id="heading-step-8-implement-calendar-helper-functions"><strong>Step 8: Implement Calendar Helper Functions</strong></h3>
<p>Below the <code>body</code> property of the <code>ContentView</code> struct, add the following extension to implement helper functions for the calendar:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">ContentView</span> </span>{
    <span class="hljs-comment">// Load current year and month</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">showToday</span><span class="hljs-params">()</span></span> {
        year = calendar.component(.year, from: <span class="hljs-type">Date</span>())
        month = calendar.component(.month, from: <span class="hljs-type">Date</span>())
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getCalendarDays</span><span class="hljs-params">()</span></span> -&gt; [<span class="hljs-type">Date</span>] {
        <span class="hljs-keyword">let</span> startDate = calendar.date(from: <span class="hljs-type">DateComponents</span>(year: year, month: month))!
        <span class="hljs-keyword">return</span> getDatesForMonthToPresent(<span class="hljs-keyword">for</span>: startDate)
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isCurrentMonth</span><span class="hljs-params">(date: Date)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">let</span> components = calendar.dateComponents([.year, .month], from: date)
        <span class="hljs-keyword">return</span> components.month == month &amp;&amp; components.year == year
    }

    <span class="hljs-comment">// Calendar functions go here</span>

    <span class="hljs-comment">// Date functions go here</span>
}
</code></pre>
<p>In this step, we added an extension to the <code>ContentView</code> struct to include helper functions for the calendar. The <code>showToday()</code> function sets the <code>year</code> and <code>month</code> variables to the current date. The <code>getCalendarDays()</code> function retrieves the dates for the current month. The <code>isCurrentMonth()</code> function checks if a given date belongs to the current month.</p>
<h3 id="heading-step-9-implement-calendar-functions"><strong>Step 9: Implement Calendar Functions</strong></h3>
<p>Inside the extension, add the following code to implement the calendar functions:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Get all dates of a month</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getDatesInMonth</span><span class="hljs-params">(dateInterval: DateInterval, dateComponent: DateComponents)</span></span> -&gt; [<span class="hljs-type">Date</span>] {
    <span class="hljs-keyword">var</span> dates: [<span class="hljs-type">Date</span>] = []
    dates.append(dateInterval.start)

    calendar.enumerateDates(startingAfter: dateInterval.start, matching: dateComponent, matchingPolicy: .nextTime) { date, <span class="hljs-number">_</span>, stop <span class="hljs-keyword">in</span>
        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> date = date <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-keyword">if</span> date &lt; dateInterval.end {
            dates.append(date)
        } <span class="hljs-keyword">else</span> {
            stop = <span class="hljs-literal">true</span>
        }
    }

    <span class="hljs-keyword">return</span> dates
}

<span class="hljs-comment">// Get all dates of a month + ending days from last month + startings days from next month</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getDatesForMonthToPresent</span><span class="hljs-params">(<span class="hljs-keyword">for</span> month: Date)</span></span> -&gt; [<span class="hljs-type">Date</span>] {
    <span class="hljs-keyword">guard</span>
        <span class="hljs-keyword">let</span> monthInterval = calendar.dateInterval(of: .month, <span class="hljs-keyword">for</span>: month),
        <span class="hljs-keyword">let</span> monthFirstWeek = calendar.dateInterval(of: .weekOfMonth, <span class="hljs-keyword">for</span>: monthInterval.start),
        <span class="hljs-keyword">let</span> monthLastWeek = calendar.dateInterval(of: .weekOfMonth, <span class="hljs-keyword">for</span>: monthInterval.end)
    <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> []
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>.getDatesInMonth(
        dateInterval: <span class="hljs-type">DateInterval</span>(start: monthFirstWeek.start, end: monthLastWeek.end),
        dateComponent: <span class="hljs-type">DateComponents</span>(hour: <span class="hljs-number">0</span>, minute: <span class="hljs-number">0</span>, second: <span class="hljs-number">0</span>)
    )
}

<span class="hljs-comment">// Other date functions go here</span>
</code></pre>
<p>In this step, we implemented two calendar functions. The <code>getDatesInMonth()</code> function retrieves all the dates within a given month. The <code>getDatesForMonthToPresent()</code> function returns the dates for the current month, including the ending days from the last month and the starting days from the next month.</p>
<h3 id="heading-step-10-implement-date-functions"><strong>Step 10: Implement Date Functions</strong></h3>
<p>Inside the extension, add the following code to implement the date functions:</p>
<pre><code class="lang-swift"><span class="hljs-comment">// Check if two dates are the same day</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isSameDay</span><span class="hljs-params">(<span class="hljs-number">_</span> date1: Date, <span class="hljs-number">_</span> date2: Date)</span></span> -&gt; <span class="hljs-type">Bool</span> {
    <span class="hljs-keyword">let</span> components: <span class="hljs-type">Set</span>&lt;<span class="hljs-type">Calendar</span>.<span class="hljs-type">Component</span>&gt; = [.year, .month, .day]
    <span class="hljs-keyword">return</span> calendar.dateComponents(components, from: date1) == calendar.dateComponents(components, from: date2)
}
</code></pre>
<p>In this step, we implemented the <code>isSameDay()</code> function, which checks if two dates are the same day by comparing their year, month, and day components.</p>
<h3 id="heading-step-11-complete-the-calendar-view"><strong>Step 11: Complete the Calendar View</strong></h3>
<p>Finally, replace the existing <code>ContentView</code> struct in the <code>ContentView.swift</code> file with the following code:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> month = <span class="hljs-number">1</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> year = <span class="hljs-number">1970</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDate = <span class="hljs-type">Date</span>()
    <span class="hljs-keyword">let</span> skyblue: <span class="hljs-type">Color</span> = .<span class="hljs-keyword">init</span>(red: <span class="hljs-number">118</span>/<span class="hljs-number">255</span>, green: <span class="hljs-number">169</span>/<span class="hljs-number">255</span>, blue: <span class="hljs-number">255</span>/<span class="hljs-number">255</span>)
    <span class="hljs-keyword">let</span> crimson: <span class="hljs-type">Color</span> = .<span class="hljs-keyword">init</span>(red: <span class="hljs-number">233</span>/<span class="hljs-number">255</span>, green: <span class="hljs-number">28</span>/<span class="hljs-number">255</span>, blue: <span class="hljs-number">76</span>/<span class="hljs-number">255</span>)
    <span class="hljs-keyword">let</span> calendar = <span class="hljs-type">Calendar</span>.current
    <span class="hljs-keyword">let</span> dateFormatter: <span class="hljs-type">DateFormatter</span> = {
        <span class="hljs-keyword">let</span> formatter = <span class="hljs-type">DateFormatter</span>()
        formatter.dateFormat = <span class="hljs-string">"d"</span>
        <span class="hljs-keyword">return</span> formatter
    }()

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">HStack</span> {
                <span class="hljs-type">Spacer</span>()
                <span class="hljs-type">Text</span>(<span class="hljs-string">"\\(calendar.monthSymbols[month - 1]) \\(String(year))"</span>)
                    .font(.title)
                    .fontDesign(.monospaced)
                <span class="hljs-type">Spacer</span>()
                <span class="hljs-type">Button</span> {
                    showToday()
                } label: {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"Today"</span>)
                        .bold()
                }
            }
            <span class="hljs-type">HStack</span>(spacing: <span class="hljs-number">2</span>) {
                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"chevron.backward.circle.fill"</span>)
                    .resizable()
                    .scaledToFit()
                    .foregroundColor(.secondary)
                    .frame(width: <span class="hljs-number">35</span>, height: <span class="hljs-number">35</span>)
                    .onTapGesture {
                        navigateToPreviousMonth()
                    }

                <span class="hljs-type">LazyVGrid</span>(columns: <span class="hljs-type">Array</span>(repeating: <span class="hljs-type">GridItem</span>(), <span class="hljs-built_in">count</span>: <span class="hljs-number">7</span>), spacing: <span class="hljs-number">10</span>) {
                    <span class="hljs-type">Group</span> {
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"SUN"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"MON"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"TUE"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"WED"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"THU"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"FRI"</span>)
                        <span class="hljs-type">Text</span>(<span class="hljs-string">"SAT"</span>)
                    }
                    .bold()
                    .foregroundColor(.secondary)
                    .fontDesign(.monospaced)

                    <span class="hljs-type">ForEach</span>(getCalendarDays(), id: \\.<span class="hljs-keyword">self</span>) { date <span class="hljs-keyword">in</span>
                        <span class="hljs-type">ZStack</span> {
                            <span class="hljs-type">Circle</span>()
                                .foregroundColor(isSameDay(date, <span class="hljs-type">Date</span>()) ? crimson : .clear)
                                .frame(width: <span class="hljs-number">35</span>, height: <span class="hljs-number">35</span>)

                            <span class="hljs-type">Circle</span>()
                                .foregroundColor(isSameDay(date, selectedDate) ? skyblue : .clear)
                                .frame(width: <span class="hljs-number">25</span>, height: <span class="hljs-number">25</span>)

                            <span class="hljs-type">Text</span>(dateFormatter.string(from: date))
                                .font(.headline)
                                .bold()
                                .foregroundColor(isCurrentMonth(date: date) ? .primary : .secondary)
                                .frame(width: <span class="hljs-number">25</span>, height: <span class="hljs-number">25</span>)
                        }
                        .onTapGesture {
                            selectedDate = date
                        }
                    }
                }
                .frame(width: <span class="hljs-type">UIScreen</span>.main.bounds.width*<span class="hljs-number">0.8</span>)

                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"chevron.forward.circle.fill"</span>)
                    .resizable()
                    .scaledToFit()
                    .foregroundColor(.secondary)
                    .frame(width: <span class="hljs-number">35</span>, height: <span class="hljs-number">35</span>)
                    .onTapGesture {
                        navigateToNextMonth()
                    }
            }
            .padding(.horizontal, <span class="hljs-number">20</span>)
        }
        .padding()
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">showToday</span><span class="hljs-params">()</span></span> {
        year = calendar.component(.year, from: <span class="hljs-type">Date</span>())
        month = calendar.component(.month, from: <span class="hljs-type">Date</span>())
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">navigateToPreviousMonth</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> month == <span class="hljs-number">1</span> {
            year -= <span class="hljs-number">1</span>
            month = <span class="hljs-number">12</span>
        } <span class="hljs-keyword">else</span> {
            month -= <span class="hljs-number">1</span>
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">navigateToNextMonth</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> month == <span class="hljs-number">12</span> {
            year += <span class="hljs-number">1</span>
            month = <span class="hljs-number">1</span>
        } <span class="hljs-keyword">else</span> {
            month += <span class="hljs-number">1</span>
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getCalendarDays</span><span class="hljs-params">()</span></span> -&gt; [<span class="hljs-type">Date</span>] {
        <span class="hljs-keyword">let</span> startDate = calendar.date(from: <span class="hljs-type">DateComponents</span>(year: year, month: month))!
        <span class="hljs-keyword">return</span> getDatesForMonthToPresent(<span class="hljs-keyword">for</span>: startDate)
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isCurrentMonth</span><span class="hljs-params">(date: Date)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">let</span> components = calendar.dateComponents([.year, .month], from: date)
        <span class="hljs-keyword">return</span> components.month == month &amp;&amp; components.year == year
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getDatesInMonth</span><span class="hljs-params">(dateInterval: DateInterval, dateComponent: DateComponents)</span></span> -&gt; [<span class="hljs-type">Date</span>] {
        <span class="hljs-keyword">var</span> dates: [<span class="hljs-type">Date</span>] = []
        dates.append(dateInterval.start)

        calendar.enumerateDates(startingAfter: dateInterval.start, matching: dateComponent, matchingPolicy: .nextTime) { date, <span class="hljs-number">_</span>, stop <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> date = date <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span>
            }

            <span class="hljs-keyword">if</span> date &lt; dateInterval.end {
                dates.append(date)
            } <span class="hljs-keyword">else</span> {
                stop = <span class="hljs-literal">true</span>
            }
        }

        <span class="hljs-keyword">return</span> dates
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getDatesForMonthToPresent</span><span class="hljs-params">(<span class="hljs-keyword">for</span> month: Date)</span></span> -&gt; [<span class="hljs-type">Date</span>] {
        <span class="hljs-keyword">guard</span>
            <span class="hljs-keyword">let</span> monthInterval = calendar.dateInterval(of: .month, <span class="hljs-keyword">for</span>: month),
            <span class="hljs-keyword">let</span> monthFirstWeek = calendar.dateInterval(of: .weekOfMonth, <span class="hljs-keyword">for</span>: monthInterval.start),
            <span class="hljs-keyword">let</span> monthLastWeek = calendar.dateInterval(of: .weekOfMonth, <span class="hljs-keyword">for</span>: monthInterval.end)
        <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> []
        }

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>.getDatesInMonth(
            dateInterval: <span class="hljs-type">DateInterval</span>(start: monthFirstWeek.start, end: monthLastWeek.end),
            dateComponent: <span class="hljs-type">DateComponents</span>(hour: <span class="hljs-number">0</span>, minute: <span class="hljs-number">0</span>, second: <span class="hljs-number">0</span>)
        )
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isSameDay</span><span class="hljs-params">(<span class="hljs-number">_</span> date1: Date, <span class="hljs-number">_</span> date2: Date)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">let</span> components: <span class="hljs-type">Set</span>&lt;<span class="hljs-type">Calendar</span>.<span class="hljs-type">Component</span>&gt; = [.year, .month, .day]
        <span class="hljs-keyword">return</span> calendar.dateComponents(components, from: date1) == calendar.dateComponents(components, from: date2)
    }
}
</code></pre>
<p>This completes the implementation of the calendar view. Run the app, and you should see a calendar interface with navigation buttons, the month and year displayed, and the ability to select dates. The selected date will be highlighted with a sky blue circle, and today's date will be highlighted with a crimson circle.</p>
]]></content:encoded></item><item><title><![CDATA[Enumerated Array in SwiftUI]]></title><description><![CDATA[Enumerated Array in SwiftUI
As you can see from the cover, in today’s post, I’m going to demonstrate how to create a dynamic list of transactions in SwiftUI using an enumerated array to make background color alternating. A ForEach would do the trick ...]]></description><link>https://xavier7t.com/enumerated-array-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/enumerated-array-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[Enumerated]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sun, 28 May 2023 03:02:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685242714942/ef34f669-e0c9-43db-9c2d-56085d963e4b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-enumerated-array-in-swiftui">Enumerated Array in SwiftUI</h1>
<p>As you can see from the cover, in today’s post, I’m going to demonstrate how to create a dynamic list of transactions in SwiftUI using an enumerated array to make background color alternating. A ForEach would do the trick for the list, however, to make the row background conditional, we need to have access to the index of each row inside ForEach. In short, we can use an array of enumerated array. Continue reading to learn how.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202305-May%202023/DemoEnumerated20230527.swift">here</a>.</p>
<p>If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios">buymeacoffee.com/xavierios</a></p>
<h1 id="heading-transaction-model">Transaction Model</h1>
<p>First of all, let’s build a model for the transaction data.</p>
<p>This struct conforms to the Identifiable protocol, which means it has a unique identifier. The struct has three properties:</p>
<ol>
<li><p><code>id</code>: This property is of type UUID (Universally Unique Identifier) and is initialized with a randomly generated unique identifier using the UUID() initializer.</p>
</li>
<li><p><code>date</code>: This property represents a date and is of type Date.</p>
</li>
<li><p><code>amount</code>: This property represents a numeric amount and is of type Double.</p>
</li>
</ol>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Transaction</span>: <span class="hljs-title">Identifiable</span> </span>{
        <span class="hljs-keyword">let</span> id = <span class="hljs-type">UUID</span>()
        <span class="hljs-keyword">let</span> date: <span class="hljs-type">Date</span>
        <span class="hljs-keyword">let</span> amount: <span class="hljs-type">Double</span>
    }
</code></pre>
<h1 id="heading-array-of-transactions">Array of Transactions</h1>
<p>The next step is to prepare an array of transactions to be displayed. Let’s use a private state property.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> transactions: [<span class="hljs-type">Transaction</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {}
    }
}
</code></pre>
<p>And then populate the array with random data when the view loads. We can do this inside an onAppear view modifier. Then we need to populate the array and we can do this by generating 50 random transactions with dates ranging from 2010 to 2022 and amounts between 10 and 200.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> transactions: [<span class="hljs-type">Transaction</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">VStack</span> {}
                .onAppear {
                        <span class="hljs-keyword">for</span> <span class="hljs-number">_</span> <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>...<span class="hljs-number">49</span> {
                    transactions.append(.<span class="hljs-keyword">init</span>(
                        date: <span class="hljs-type">Calendar</span>.current.date(from: .<span class="hljs-keyword">init</span>(year: <span class="hljs-type">Int</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">2010</span>...<span class="hljs-number">2022</span>), month: <span class="hljs-type">Int</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">2</span>...<span class="hljs-number">10</span>), day: <span class="hljs-type">Int</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">1</span>...<span class="hljs-number">20</span>)))!,
                        amount: <span class="hljs-type">Double</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">10</span>...<span class="hljs-number">200</span>))
                    )
                }
                transactions.<span class="hljs-built_in">sort</span> { $<span class="hljs-number">0</span>.date &gt; $<span class="hljs-number">1</span>.date }
                }
    }
}
</code></pre>
<ul>
<li><p>The <code>date</code> property is set to a randomly generated date between the years 2010 and 2022, with a random month between 2 and 10, and a random day between 1 and 20. The <a target="_blank" href="http://Calendar.current.date"><code>Calendar.current.date</code></a><code>(from:)</code> method is used to create a <code>Date</code> object from the specified components.</p>
</li>
<li><p>The <code>amount</code> property is set to a random double value between 10 and 200.</p>
</li>
</ul>
<p>And last step of the data prep is to sort the transactions in descending order based on their dates.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> transactions: [<span class="hljs-type">Transaction</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">VStack</span> {}
                .onAppear {
                        <span class="hljs-keyword">for</span> <span class="hljs-number">_</span> <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>...<span class="hljs-number">49</span> {
                    transactions.append(.<span class="hljs-keyword">init</span>(
                        date: <span class="hljs-type">Calendar</span>.current.date(from: .<span class="hljs-keyword">init</span>(year: <span class="hljs-type">Int</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">2010</span>...<span class="hljs-number">2022</span>), month: <span class="hljs-type">Int</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">2</span>...<span class="hljs-number">10</span>), day: <span class="hljs-type">Int</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">1</span>...<span class="hljs-number">20</span>)))!,
                        amount: <span class="hljs-type">Double</span>.random(<span class="hljs-keyword">in</span>: <span class="hljs-number">10</span>...<span class="hljs-number">200</span>))
                    )
                }
                                <span class="hljs-comment">// ------ New Code Below -------</span>
                transactions.<span class="hljs-built_in">sort</span> { $<span class="hljs-number">0</span>.date &gt; $<span class="hljs-number">1</span>.date }
                }
    }
}
</code></pre>
<p>After the loop, the <code>transactions</code> array is sorted in descending order based on the <code>date</code> property using the <code>sort</code> method and a closure. The <code>$0</code> and <code>$1</code> are shorthand arguments referring to two elements being compared, and the closure specifies the sorting criteria (<code>$</code><a target="_blank" href="http://0.date"><code>0.date</code></a> <code>&gt; $</code><a target="_blank" href="http://1.date"><code>1.date</code></a>), meaning it sorts the transactions based on the date property in descending order.</p>
<h1 id="heading-ui-setup">UI Setup</h1>
<p>Now let’s set up the UI before moving forward:</p>
<p>Embed the <code>VStack</code> inside a <code>NavigationView</code> and change the <code>VStack</code> to a <code>ScrollView</code>. Then give it a navigation title of “<strong>Transaction Records</strong>”.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
        @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> transactions: [<span class="hljs-type">Transaction</span>] = []
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">NavigationView</span> {
                <span class="hljs-type">ScrollView</span> {

                }
                .navigationTitle(<span class="hljs-string">"Transaction Records"</span>)
            }
            .onAppear {
                                <span class="hljs-comment">//... code from above</span>
            }
        }
    }
</code></pre>
<h1 id="heading-build-the-list-with-foreach">Build the list with ForEach</h1>
<p>Now inside the <code>ScrollView</code>, we need a <code>ForEach</code> to iterate over the transactions.</p>
<pre><code class="lang-swift"><span class="hljs-type">ForEach</span>(transactions) { transaction <span class="hljs-keyword">in</span>
                        <span class="hljs-type">HStack</span> {
                            <span class="hljs-type">Text</span>(transaction.date.formatted(date: .abbreviated, time: .omitted))
                            <span class="hljs-type">Spacer</span>()
                            <span class="hljs-type">Text</span>(<span class="hljs-string">"$"</span> + transaction.amount.toString1(<span class="hljs-number">2</span>))
                        }
                        .padding(.horizontal, <span class="hljs-number">20</span>)
                        .padding(.vertical, <span class="hljs-number">5</span>)
                    }
</code></pre>
<p>The code above is a <code>ForEach</code> loop that iterates over the <code>transactions</code> array and creates a view for each element in the array.</p>
<p>Inside the loop, a <code>HStack</code> view is created to display the transaction information. It consists of two <code>Text</code> views and a <code>Spacer</code>.</p>
<p>The first <code>Text</code> view displays the formatted date of the transaction using the <code>formatted</code> method. It specifies the date style as <code>.abbreviated</code>, which will display the date in an abbreviated format, and the time style as <code>.omitted</code>, which will exclude the time component.</p>
<p>The second <code>Text</code> view displays the amount of the transaction. The amount is converted to a string with two decimal places using the <code>String(format, value)</code> method, and then concatenated with the "$" symbol.</p>
<p>The <code>HStack</code> view is then modified with padding using the <code>.padding</code> modifier. It adds horizontal padding of 20 points and vertical padding of 5 points to the view.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685242832622/46617eb7-fc29-4bda-9f30-2d232703352a.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-background-color-time">Background Color Time!</h1>
<p>Now it’s time to work on the background color alternating between rows.</p>
<p>Since we need the index of each row, we can use <code>enumerated()</code> function to access the index. However, this method returns a type called <code>EnumeratedSequence</code> and we need an array for ForEach, hence we need an extra wrapper to convert it back to an array. The item inside the array will be a pair of index (offset) and the element (transaction).</p>
<pre><code class="lang-swift"><span class="hljs-type">ForEach</span>(<span class="hljs-type">Array</span>(transactions.enumerated()), id: \\.element.id) { offset, transaction <span class="hljs-keyword">in</span>
                        <span class="hljs-type">HStack</span> {
                            <span class="hljs-type">Text</span>(<span class="hljs-string">"\\(offset + 1)"</span>).frame(width: <span class="hljs-number">40</span>)
                            <span class="hljs-type">Text</span>(transaction.date.formatted(date: .abbreviated, time: .omitted))
                            <span class="hljs-type">Spacer</span>()
                            <span class="hljs-type">Text</span>(<span class="hljs-string">"$"</span> + transaction.amount.toString1(<span class="hljs-number">2</span>))
                        }
                        .padding(.horizontal, <span class="hljs-number">10</span>)
                        .padding(.vertical, <span class="hljs-number">11</span>)
                        .background(offset % <span class="hljs-number">2</span> == <span class="hljs-number">0</span> ? <span class="hljs-type">Color</span>.secondary.opacity(<span class="hljs-number">0.5</span>) : <span class="hljs-type">Color</span>.clear)
                    }
</code></pre>
<p>This time we use <code>Array(transactions.enumerated())</code> to get pairs of index and transaction. And we need to specify the id with a keypath <code>\\.</code><a target="_blank" href="http://element.id"><code>element.id</code></a>. The ForEach closure signature also updates from <code>transaction</code> to <code>offset, transaction</code>.</p>
<p>Then inside the HStack we add an extra Text View to display the offset value added by one as the row number.</p>
<p>And finally, we use a <code>background</code> view modifier to make the conditional background color, whose value is set with a ternary operator, checking if the offset value is even. If yes, the background color will be secondary, otherwise, it’s set to clear. Et voilà!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685242814931/56574b78-3c51-4d9a-92a7-e80301c6e529.png" alt class="image--center mx-auto" /></p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[Section and Navigation Link in SwiftUI]]></title><description><![CDATA[The Settings app is an essential part of the iOS ecosystem, allowing users to configure their devices and manage their apps. With SwiftUI, it's easier than ever to create beautiful and intuitive user interfaces for iOS apps. In this blog post, we'll ...]]></description><link>https://xavier7t.com/section-and-navigation-link-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/section-and-navigation-link-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[UI]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Fri, 05 May 2023 05:14:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683263587304/9cab07a1-1904-4611-bdd9-6a9768293236.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Settings app is an essential part of the iOS ecosystem, allowing users to configure their devices and manage their apps. With SwiftUI, it's easier than ever to create beautiful and intuitive user interfaces for iOS apps. In this blog post, we'll show you how to use SwiftUI to create a Settings app UI that looks and feels just like the real thing. We'll walk you through the process of creating the UI step-by-step, so you can follow along and create your own Settings app UI in no time. So, let's get started!</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202305-May%202023/DemoSettingsView20230505.swift">here</a>.</p>
<p>If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios">buymeacoffee.com/xavierios</a></p>
<h3 id="heading-set-up-the-basic-view-structure"><strong>Set up the basic view structure</strong></h3>
<p>In the <code>SettingsView</code> struct, start by creating a <code>NavigationView</code> and a <code>List</code> view inside it. The <code>List</code> will contain the different sections and settings items.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SettingsView</span>: <span class="hljs-title">View</span> </span>{
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">NavigationView</span> {
            <span class="hljs-type">List</span> {
                <span class="hljs-comment">// settings sections and items will go here</span>
            }
            .listStyle(<span class="hljs-type">GroupedListStyle</span>())
            .navigationTitle(<span class="hljs-string">"Settings"</span>)
        }
    }
}
</code></pre>
<p>Here, we're also adding a <code>GroupedListStyle</code> to the <code>List</code> and setting the navigation title to "Settings".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683263052867/e94e6667-6a07-442a-8713-ba9d3bb2d7ce.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-add-the-settings-sections-and-items"><strong>Add the settings sections and items</strong></h3>
<p>Inside the <code>List</code>, create the different <code>Section</code> views for each group of settings items. Then, add <code>NavigationLink</code> views inside each section to represent the different settings items.</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SettingsView</span>: <span class="hljs-title">View</span> </span>{
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">NavigationView</span> {
                <span class="hljs-type">List</span> {
                    <span class="hljs-type">Section</span>(header: <span class="hljs-type">Text</span>(<span class="hljs-string">"GENERAL"</span>)) {
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"Do Not Disturb"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"moon"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"Do Not Disturb"</span>)
                            }
                        }
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"Display &amp; Brightness"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"textformat.size"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"Display &amp; Brightness"</span>)
                            }
                        }
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"Sounds &amp; Haptics"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"speaker.2"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"Sounds &amp; Haptics"</span>)
                            }
                        }
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"Screen Time"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"hourglass"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"Screen Time"</span>)
                            }
                        }
                    }
                    <span class="hljs-type">Section</span>(header: <span class="hljs-type">Text</span>(<span class="hljs-string">"ACCOUNTS"</span>)) {
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"iCloud"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"icloud"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"iCloud"</span>)
                            }
                        }
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"Password &amp; Security"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"lock"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"Password &amp; Security"</span>)
                            }
                        }
                    }
                    <span class="hljs-type">Section</span>(header: <span class="hljs-type">Text</span>(<span class="hljs-string">"ABOUT"</span>)) {
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"General"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"info.circle"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"General"</span>)
                            }
                        }
                        <span class="hljs-type">NavigationLink</span>(destination: <span class="hljs-type">Text</span>(<span class="hljs-string">"Software Update"</span>)) {
                            <span class="hljs-type">HStack</span> {
                                <span class="hljs-type">Image</span>(systemName: <span class="hljs-string">"arrow.up.right.circle"</span>)
                                <span class="hljs-type">Text</span>(<span class="hljs-string">"Software Update"</span>)
                            }
                        }
                    }
                }
                .listStyle(<span class="hljs-type">GroupedListStyle</span>())
                .navigationTitle(<span class="hljs-string">"Settings"</span>)
            }
        }
    }
</code></pre>
<p>Here, we're using <code>header</code> to add a title to each section, and <code>destination</code> to specify the detail view that should be shown when the user taps on the <code>NavigationLink</code>. We're also using a <code>HStack</code> to combine an image (using the <code>Image</code> view with a system name) and a text label (using the <code>Text</code> view).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683263188610/f3b40eb1-b702-49a7-a107-502379303da0.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-liststyle">ListStyle</h1>
<p>We can make the the section rows more like rounded rectangles by changing the value of the view modifier <code>.listStyle</code> from <code>GroupedListStyle()</code> to <code>InsetGroupedListStyle()</code>, or even simpler <code>.insetGrouped</code>.</p>
<pre><code class="lang-swift">.listStyle(.insetGrouped)
</code></pre>
<p>or</p>
<pre><code class="lang-swift">.listStyle(<span class="hljs-type">InsetGroupedListStyle</span>())
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683263393931/dacd04ea-3181-4884-ab97-2cbf69d9eab1.png" alt class="image--center mx-auto" /></p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[Rotation Effect and Animation in SwiftUI]]></title><description><![CDATA[Loading data is an essential task in any app that communicates with a server or performs intensive computations. While the data is loading, it's a good practice to show a loading indicator or an animated view to provide feedback to the user and preve...]]></description><link>https://xavier7t.com/rotation-effect-and-animation-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/rotation-effect-and-animation-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[animation]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Thu, 04 May 2023 03:39:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683171430977/b0213967-056f-46d7-9583-fd5819e403a8.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Loading data is an essential task in any app that communicates with a server or performs intensive computations. While the data is loading, it's a good practice to show a loading indicator or an animated view to provide feedback to the user and prevent them from getting frustrated. In this blog post, we will explore how to create an animating view in SwiftUI while loading data.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202305-May%202023/DemoLoadingAnimation20230503.swift">here</a>.</p>
<p>If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios">buymeacoffee.com/xavierios</a></p>
<h1 id="heading-step-1-create-a-view-model">Step 1: Create a View Model</h1>
<p>The first step is to create a view model that will be responsible for loading the data. The view model should have a method that starts loading the data and sets a property to indicate whether the data is being loaded or not.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewModel</span>: <span class="hljs-title">ObservableObject</span> </span>{
  @<span class="hljs-type">Published</span> <span class="hljs-keyword">var</span> isLoading = <span class="hljs-literal">false</span>
  <span class="hljs-keyword">var</span> data: [<span class="hljs-type">String</span>] = []

  <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadData</span><span class="hljs-params">()</span></span> {
    isLoading = <span class="hljs-literal">true</span>
    <span class="hljs-comment">// Code to load data goes here</span>
    <span class="hljs-type">DispatchQueue</span>.main.asyncAfter(deadline: .now() + <span class="hljs-number">2</span>) { <span class="hljs-comment">// Simulate loading delay</span>
      <span class="hljs-keyword">self</span>.data = [<span class="hljs-string">"Data 1"</span>, <span class="hljs-string">"Data 2"</span>, <span class="hljs-string">"Data 3"</span>]
      <span class="hljs-keyword">self</span>.isLoading = <span class="hljs-literal">false</span>
    }
  }
}
</code></pre>
<p>In this example, we use the <code>@Published</code> property wrapper to publish the <code>isLoading</code> property and allow it to be observed by the view. The <code>loadData</code> method simulates loading data with a delay of 2 seconds and updates the <code>data</code> property and the <code>isLoading</code> property accordingly.</p>
<h1 id="heading-step-2-create-an-animating-view">Step 2: Create an Animating View</h1>
<p>The next step is to create an animating view that will be displayed while the data is being loaded. In this example, we will create a simple spinner view that rotates continuously.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">SpinnerView</span>: <span class="hljs-title">View</span> </span>{
  @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> isAnimating = <span class="hljs-literal">false</span>

  <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
    <span class="hljs-type">VStack</span> {
      <span class="hljs-type">Circle</span>()
        .trim(from: <span class="hljs-number">0</span>, to: <span class="hljs-number">0.7</span>)
        .stroke(<span class="hljs-type">Color</span>.blue, lineWidth: <span class="hljs-number">4</span>)
        .frame(width: <span class="hljs-number">50</span>, height: <span class="hljs-number">50</span>)
        .rotationEffect(<span class="hljs-type">Angle</span>(degrees: isAnimating ? <span class="hljs-number">360</span> : <span class="hljs-number">0</span>))
        .animation(<span class="hljs-type">Animation</span>.linear(duration: <span class="hljs-number">3</span>).repeatForever(autoreverses: <span class="hljs-literal">false</span>), value: <span class="hljs-type">UUID</span>())
        .onAppear {
          <span class="hljs-keyword">self</span>.isAnimating = <span class="hljs-literal">true</span>
        }
    }
  }
}
</code></pre>
<p>In this example, we use the <code>Circle</code> shape to create the spinner and the <code>rotationEffect</code> modifier to rotate it continuously. We also use the <code>animation</code> modifier to animate the rotation and the <code>onAppear</code> modifier to start the animation when the view appears.</p>
<h1 id="heading-step-3-create-the-main-view">Step 3: Create the Main View</h1>
<p>The final step is to create the main view that will display the animating view while the data is being loaded. In this example, we will use the <code>if</code> statement to conditionally display the spinner view or the loaded data based on the value of the <code>isLoading</code> property.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
  @<span class="hljs-type">StateObject</span> <span class="hljs-keyword">var</span> viewModel = <span class="hljs-type">ViewModel</span>()

  <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
    <span class="hljs-type">VStack</span> {
      <span class="hljs-keyword">if</span> viewModel.isLoading {
        <span class="hljs-type">SpinnerView</span>()
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-type">List</span>(viewModel.data, id: \.<span class="hljs-keyword">self</span>) { item <span class="hljs-keyword">in</span>
          <span class="hljs-type">Text</span>(item)
        }
      }
    }
    .onAppear {
      viewModel.loadData()
    }
  }
}
</code></pre>
<p>In this example, we use the <code>if</code> statement to conditionally display the <code>SpinnerView</code> or the loaded data in a <code>List</code> view. We also use the <code>onAppear</code> modifier to start loading the data when the view appears.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Creating an animating view in SwiftUI while loading data is a simple yet effective way to provide feedback to the user and prevent them from getting frustrated. By following the steps outlined in this blog post, you can easily create an animating view that fits your app’s design and style. It's worth noting that there are many different ways to create animating views in SwiftUI, and this is just one example.</p>
<p>In summary, creating an animating view in SwiftUI while loading data involves creating a view model that loads the data and sets a property to indicate whether the data is being loaded or not, creating an animating view that is displayed while the data is being loaded, and creating the main view that conditionally displays the animating view or the loaded data based on the value of the <code>isLoading</code> property. By following these steps, you can create a great user experience that makes your app feel responsive and engaging.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email. If you like my posts, 😚consider tipping me at <a target="_blank" href="http://buymeacoffee.com/xavierios">buymeacoffee.com/xavierios</a></p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[MVVM in SwiftUI]]></title><description><![CDATA[Model-View-ViewModel (MVVM) is an architectural pattern that has gained a lot of popularity in recent years, especially in the context of developing mobile applications. With the release of SwiftUI, Apple's new framework for building user interfaces,...]]></description><link>https://xavier7t.com/mvvm-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/mvvm-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[MVVM]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Wed, 03 May 2023 03:56:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683086384759/a2974e21-e035-4980-99b6-c28d739810fd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Model-View-ViewModel (MVVM) is an architectural pattern that has gained a lot of popularity in recent years, especially in the context of developing mobile applications. With the release of SwiftUI, Apple's new framework for building user interfaces, MVVM has become even more relevant. In this blog, we'll take a closer look at how MVVM can be implemented in SwiftUI with a sample list of posts.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202305-May%202023/DemoMVVM20230502.swift">here</a>.</p>
<h1 id="heading-what-the-heck-is-mvvm">What the heck is MVVM</h1>
<p>First, let's take a brief look at the three components of MVVM:</p>
<ol>
<li><p>Model: This represents the data and how the data get structured. In most cases, a model is a <code>struct</code> or multiple <code>struct</code>s.</p>
</li>
<li><p>View: This represents the user interface of the application. It includes things like buttons, labels, text fields, and other UI elements, and of course, a representation of the data in the front end.</p>
</li>
<li><p>ViewModel: This acts as a mediator between the View and the Model. It exposes data from the Model to the View and handles user interactions from the View to the Model. Basically, it handles the business logic, such as preparing data, sorting, event handling.</p>
</li>
</ol>
<h1 id="heading-implementation">Implementation</h1>
<p>Let’s create a simple List-of-Posts app to taste MVVM.</p>
<p>First of all, we need to build up the model.</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Post</span> </span>{
        <span class="hljs-keyword">let</span> id: <span class="hljs-type">Int</span>
        <span class="hljs-keyword">let</span> title: <span class="hljs-type">String</span>
        <span class="hljs-keyword">let</span> description: <span class="hljs-type">String</span>
    }
</code></pre>
<p>In the example above, we created a struct called <code>Post</code> with three properties. And later we’re going to display the content of Post items. Here Post is our model since it defines what data we are going to process.</p>
<p>Second, we build the view model to prepare the post data for the view.</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostViewModel</span>: <span class="hljs-title">ObservableObject</span> </span>{
        @<span class="hljs-type">Published</span> <span class="hljs-keyword">var</span> posts: [<span class="hljs-type">Post</span>] = []
        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getPosts</span><span class="hljs-params">()</span></span> {
            posts = [
                .<span class="hljs-keyword">init</span>(id: <span class="hljs-number">1</span>, title: <span class="hljs-string">"Lorem ipsum dolor sit amet"</span>, description: <span class="hljs-string">"consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam"</span>),
                .<span class="hljs-keyword">init</span>(id: <span class="hljs-number">2</span>, title: <span class="hljs-string">"quis nostrud exercitation"</span>, description: <span class="hljs-string">"ullamco laboris nisi ut aliquip ex ea commodo consequat"</span>),
                .<span class="hljs-keyword">init</span>(id: <span class="hljs-number">3</span>, title: <span class="hljs-string">"Duis aute irure dolor in reprehenderit"</span>, description: <span class="hljs-string">"in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</span>)
            ]
        }
    }
</code></pre>
<p>In this example, we have a class called <code>PostViewModel</code> that has a <code>posts</code> property and a function called <code>getPosts</code> that is responsible for loading the posts from an API. (For demo purpose, I’m initializing some values manually.) The <code>@Published</code> property wrapper is used to make the <code>posts</code> property observable, which allows the View to update itself whenever the property changes.</p>
<p>And finally, it comes to the view. In SwiftUI, Views are typically created using declarative syntax. This means that we define the UI elements and their properties using a hierarchy of views. Here's an example of a view that displays a list of posts:</p>
<pre><code class="lang-swift">    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
        @<span class="hljs-type">StateObject</span> <span class="hljs-keyword">var</span> vm = <span class="hljs-type">PostViewModel</span>()
        <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
            <span class="hljs-type">NavigationView</span> {
                <span class="hljs-type">List</span> {
                    <span class="hljs-type">ForEach</span>(vm.posts, id: \.id) { post <span class="hljs-keyword">in</span>
                        <span class="hljs-type">HStack</span> {
                            <span class="hljs-type">VStack</span>(alignment: .leading) {
                                <span class="hljs-type">Text</span>(post.title).bold()
                                <span class="hljs-type">Text</span>(post.description)
                                    .lineLimit(<span class="hljs-number">2</span>)
                                    .font(.footnote)
                                    .foregroundColor(.secondary)
                            }
                            <span class="hljs-type">Spacer</span>()
                            <span class="hljs-type">Text</span>(<span class="hljs-string">"\(post.id)"</span>)
                                .bold()
                                .foregroundColor(.secondary)
                                .padding()
                        }
                    }
                }
                .navigationTitle(<span class="hljs-string">"Posts - MVVM"</span>)
            }
            .onAppear {
                vm.getPosts()
            }
        }
    }
</code></pre>
<p>In this example, we have a view called <code>ContentView</code> displaying a list of posts. The view has a reference to a <code>PostViewModel</code>, which is responsible for loading the posts and providing them to the view. The <code>List</code> element is used to display the posts in a scrollable list, and each post has a row with its title, description and ID. The <code>onAppear</code> modifier calls the <code>getPosts</code> function inside the view model so that all three posts will get ready when the view loads.</p>
<p>Now that all MVVM components are done, we can check the preview canvas and you can see that all three posts are shown. Our code is simply and clean, we only have to call the <code>getPosts</code> function in the view and the view itself only defines what the UI should look like, without touching the business logic (<code>getPosts</code> function in our case).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1683085724592/f0c19f07-df22-407c-84a7-5f11c5bee28b.png" alt class="image--center mx-auto" /></p>
<p>In summary, MVVM is a powerful architectural pattern that can be used to build scalable and maintainable applications. With SwiftUI, it is easier than ever to implement MVVM in your projects. The sample list of posts shown here demonstrates how MVVM can be used to build a simple, yet functional, application.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[2 Ways to format decimal numbers in Swift]]></title><description><![CDATA[In programming, formatting numbers is an important task that helps to present data in a more readable and user-friendly way. In Swift, there are several ways to format decimal places, including using string interpolation, NSNumberFormatter, and the D...]]></description><link>https://xavier7t.com/2-ways-to-format-decimal-numbers-in-swift</link><guid isPermaLink="true">https://xavier7t.com/2-ways-to-format-decimal-numbers-in-swift</guid><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iOS]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[number formatting]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Tue, 02 May 2023 04:27:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683001578453/57a551aa-88df-4731-b804-d3cd7f078350.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In programming, formatting numbers is an important task that helps to present data in a more readable and user-friendly way. In Swift, there are several ways to format decimal places, including using string interpolation, NSNumberFormatter, and the Decimal struct. In this blog, we will explore each method with code examples.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202305-May%202023/DemoDecimalFormatter20230501.swift">here</a>.</p>
<h1 id="heading-using-string-interpolation-formatter">Using String Interpolation formatter</h1>
<p>One way to format decimal places in Swift is by using string interpolation. You can use the String(format: ) method to specify the number of decimal places you want to display. Here's an example:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">Double</span> </span>{
    <span class="hljs-comment">//MARK: - Using string interpolation</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">toString1</span><span class="hljs-params">(<span class="hljs-number">_</span> numOfDecimal: Int)</span></span> -&gt; <span class="hljs-type">String</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">String</span>(format: <span class="hljs-string">"%.\(numOfDecimal)f"</span>, <span class="hljs-keyword">self</span>)
    }
}
</code></pre>
<p>In this example, we used the format specifier to indicate that we want to display how many decimal places after the decimal point. For instance, if the integer passed into the function is 2, the format specifier would be "%.2f" and the result of <code>Double(3).toString1(2)</code> is <code>"3.00"</code>.</p>
<h1 id="heading-using-nsnumber-formatter">Using NSNumber Formatter</h1>
<p>NumberFormatter is a class in Swift that allows you to format NSNumbers in various ways, including specifying the number of decimal places to display. Here's an example:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">extension</span> <span class="hljs-title">Double</span> </span>{
    <span class="hljs-comment">//MARK: - Using NSNumberFormatter</span>
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">toString2</span><span class="hljs-params">(<span class="hljs-number">_</span> numOfDecimal: Int)</span></span> -&gt; <span class="hljs-type">String</span> {
        <span class="hljs-keyword">let</span> formatter = <span class="hljs-type">NumberFormatter</span>()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = numOfDecimal
        <span class="hljs-keyword">return</span> formatter.string(from: <span class="hljs-keyword">self</span> <span class="hljs-keyword">as</span> <span class="hljs-type">NSNumber</span>) ?? <span class="hljs-string">""</span>
    }
}
</code></pre>
<p>In this example, we created an instance of NumberFormatter and set the numberStyle property to .decimal to format the number with decimal separators. We also set the maximumFractionDigits property to 2 to display two decimal places after the decimal point, if <code>numOfDecimal</code> is 2.</p>
<h1 id="heading-usage-of-the-functions-above">Usage of the functions above</h1>
<p>We can build a simple SwiftUI view to check how the function can be used.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    <span class="hljs-keyword">let</span> pi = <span class="hljs-type">Double</span>.pi
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> digit: <span class="hljs-type">Int</span> = <span class="hljs-number">0</span>
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">NavigationView</span> {

            <span class="hljs-type">VStack</span> {
                <span class="hljs-type">Stepper</span>(<span class="hljs-string">"Number of digit (0-16)"</span>, value: $digit)
                    .onChange(of: digit) { newValue <span class="hljs-keyword">in</span>
                        <span class="hljs-keyword">if</span> newValue &lt; <span class="hljs-number">0</span> {
                            digit = <span class="hljs-number">0</span>
                        }
                        <span class="hljs-keyword">if</span> newValue &gt;= <span class="hljs-number">16</span> {
                            digit = newValue - <span class="hljs-number">1</span>
                        }
                    }
                getRow(<span class="hljs-string">"Unformatted"</span>, <span class="hljs-string">"\(pi)"</span>)
                getRow(<span class="hljs-string">"String interpolation"</span>, pi.toString1(digit))
                getRow(<span class="hljs-string">"NSNumberFormatter"</span>, pi.toString2(digit))
            }
            .padding(.horizontal, <span class="hljs-number">20</span>)
        }
    }
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getRow</span><span class="hljs-params">(<span class="hljs-number">_</span> type: String, <span class="hljs-number">_</span> value: String)</span></span> -&gt; some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">Divider</span>()
            <span class="hljs-type">HStack</span> {
                <span class="hljs-type">Text</span>(type).bold()
                <span class="hljs-type">Spacer</span>()
                <span class="hljs-type">Text</span>(value)
            }
        }
    }
}
</code></pre>
<p>The SwiftUI view example above contains a function that creates rows (technically a VStack with a Divider and an HStack inside), and each HStack contains two texts separated by a Spacer, one of which is bolded.</p>
<p>The main view contains a stepper to control the digit numbers, with an onChange modifier to limit the number between 0 ~ 16 digits. The getRow function is called three times to create three rows: The first row shows the unformatted string interpolation of the math <strong><em>π</em></strong> (<code>Double.pi</code>), and the second and third rows show the value returned by the functions above inside a Text View.</p>
<p>In conclusion, formatting decimal places in Swift is easy and can be done using 2 methods, including string interpolation, and NSNumber Formatter. Depending on your needs, you can choose the method that works best for you.</p>
]]></content:encoded></item><item><title><![CDATA[EnvironmentObject in SwiftUI]]></title><description><![CDATA[In SwiftUI, Environment Object is a powerful tool for managing shared data across multiple views in your app. It allows you to create an object that can be accessed by any view in your app hierarchy and provides a convenient way to update and share d...]]></description><link>https://xavier7t.com/environmentobject-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/environmentobject-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[EnvironmentObject]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sat, 29 Apr 2023 01:22:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682731246436/105609b7-8b3e-4348-80bb-f072d0ff1ad5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In SwiftUI, Environment Object is a powerful tool for managing shared data across multiple views in your app. It allows you to create an object that can be accessed by any view in your app hierarchy and provides a convenient way to update and share data between views. In this blog post, we will explore some best practices for using Environment Object in SwiftUI.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/202304-Apr%202023/DemoEnvironmentObject20230428.swift">here</a>.</p>
<h1 id="heading-define-the-environment-object">Define the Environment Object</h1>
<p>The first step in using Environment Object is to define it. You can do this by creating a class or struct that conforms to the ObservableObject protocol, and adding the @EnvironmentObject property wrapper to any view that needs access to it. Here's an example of how to define an Environment Object:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserData</span>: <span class="hljs-title">ObservableObject</span> </span>{
    @<span class="hljs-type">Published</span> <span class="hljs-keyword">var</span> username = <span class="hljs-string">"Guest"</span>
}
</code></pre>
<p>In this example, we define a UserData class that conforms to the ObservableObject protocol, and has a published property called username.</p>
<h1 id="heading-use-the-environment-object-in-views">Use the Environment Object in Views</h1>
<p>Once you have defined your Environment Object, you can use it in your views by adding the @EnvironmentObject property wrapper. Here's an example of how to use the UserData object we defined earlier:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">EnvironmentObject</span> <span class="hljs-keyword">var</span> userData: <span class="hljs-type">UserData</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">Text</span>(<span class="hljs-string">"Welcome, \(userData.username)!"</span>)
    }
}
</code></pre>
<p>In this example, we add the @EnvironmentObject property wrapper to the userData property, and use it to display the username property in the Text view.</p>
<h1 id="heading-dont-overuse-environment-object">Don't Overuse Environment Object</h1>
<p>While Environment Object is a powerful tool, it's important to use it sparingly. Overusing Environment Object can make your code harder to read and maintain, and can lead to performance issues. Instead, consider using other data-sharing techniques such as passing data through view modifiers or using a dedicated data store.</p>
<h1 id="heading-keep-environment-object-small">Keep Environment Object Small</h1>
<p>When defining an Environment Object, it's important to keep it small and focused on a single task. For example, if you have a large data set that needs to be shared across multiple views, consider breaking it down into smaller, more focused Environment Objects.</p>
<h1 id="heading-use-lazy-initialization">Use Lazy Initialization</h1>
<p>When using Environment Object, it's a good idea to use lazy initialization to create the object. This ensures that the object is only created when it's needed, and can help to improve performance. Here's an example of how to use lazy initialization with an Environment Object:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">EnvironmentObject</span> <span class="hljs-keyword">var</span> userData: <span class="hljs-type">UserData</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Welcome, \(userData.username)!"</span>)
            <span class="hljs-type">Button</span>(action: {
                userData.username = <span class="hljs-string">"John"</span>
            }) {
                <span class="hljs-type">Text</span>(<span class="hljs-string">"Update Username"</span>)
            }
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">MainView</span>: <span class="hljs-title">View</span> </span>{
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">ContentView</span>().environmentObject(<span class="hljs-type">UserData</span>())
    }
}
</code></pre>
<p>In this example, we use lazy initialization to create the UserData object when it's needed in the ContentView view. (The instance of <code>UserData</code> is created inside <code>MainView</code> when the environmentObject is needed, instead of inside the <code>ContentView</code>.)</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Environment Object is a powerful tool for managing shared data in SwiftUI, but it's important to use it wisely. By defining small, focused Environment Objects and using lazy initialization, you can ensure that your code is easy to read and maintain, and that your app performs well. With these best practices, you can make the most of Environment Object in your SwiftUI app.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[Day of the Week Picker in SwiftUI]]></title><description><![CDATA[A day of the week picker is a simple UI element that allows the user to select a day of the week from a list of options. This is a common UI element in many apps, especially those related to scheduling or time management. In today’s post, we are goin...]]></description><link>https://xavier7t.com/day-of-the-week-picker-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/day-of-the-week-picker-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[picker]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Wed, 26 Apr 2023 03:30:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682479798129/5fec2df1-df20-4aef-b50c-9ffaaa839f45.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A day of the week picker is a simple UI element that allows the user to select a day of the week from a list of options. This is a common UI element in many apps, especially those related to scheduling or time management. In today’s post, we are going to look at how to implement a single day-of-week picker and a more custom, multiple-day version of it.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/Day%20of%20the%20Week%20Picker">here</a>.</p>
<h1 id="heading-single-day-of-week-picker-using-picker">Single Day-of-Week Picker using Picker</h1>
<p>To implement a day of the week picker in SwiftUI, we first need to create an array of the days of the week. We can do this using an enum, like this:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">Day</span>: <span class="hljs-title">String</span>, <span class="hljs-title">CaseIterable</span> </span>{
    <span class="hljs-keyword">case</span> <span class="hljs-type">Sunday</span>, <span class="hljs-type">Monday</span>, <span class="hljs-type">Tuesday</span>, <span class="hljs-type">Wednesday</span>, <span class="hljs-type">Thursday</span>, <span class="hljs-type">Friday</span>, <span class="hljs-type">Saturday</span>
}
</code></pre>
<p>Here, we've defined an enum called <code>Day</code> that has seven cases, one for each day of the week. We've also used the <code>CaseIterable</code> protocol to make it easy to iterate over all the cases of the enum.<br />Next, we can create a <code>Picker</code> view that displays the days of the week. Here's an example of how to do this:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">DayPicker</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDay = <span class="hljs-type">Day</span>.<span class="hljs-type">Monday</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">Picker</span>(<span class="hljs-string">"Day"</span>, selection: $selectedDay) {
            <span class="hljs-type">ForEach</span>(<span class="hljs-type">Day</span>.allCases, id: \.<span class="hljs-keyword">self</span>) {
                <span class="hljs-type">Text</span>($<span class="hljs-number">0</span>.rawValue).tag($<span class="hljs-number">0</span>)
            }
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682478598852/1713e022-710e-429e-8058-a3a486426ef5.png" alt class="image--center mx-auto" /></p>
<p>Here, we've defined a <code>DayPicker</code> view that contains a <code>Picker</code>. We've also defined a <code>@State</code> variable called <code>selectedDay</code> that will hold the user's selected day of the week.</p>
<p>The <code>Picker</code> itself is created using the <code>Picker</code> initializer. We pass in a string that will be used as the label for the <code>Picker</code>, and a binding to the <code>selectedDay</code> variable. This will update the variable whenever the user selects a new day of the week.</p>
<p>We then use a <code>ForEach</code> loop to create a <code>Text</code> view for each day of the week. We use the <code>id</code> parameter to ensure that each item in the loop has a unique identifier. We also use the <code>tag</code> method to set the tag of each <code>Text</code> view to the corresponding <code>Day</code> enum value.</p>
<p>Finally, we can use the <code>DayPicker</code> view in our app wherever we need a day of the week picker. For example, we could use it in a form to allow the user to schedule a recurring event on a specific day of the week.</p>
<h1 id="heading-custom-days-of-week-picker-supporting-multiple-choices">Custom Days-of-Week Picker supporting multiple choices</h1>
<p>To create a custom days of week picker, we need a <code>@State</code> property of type array of <code>Day</code> to hold the options picked. And inside the <code>body</code> property, let’s create an <code>HStack</code> to display all the options.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">DaysPicker</span>: <span class="hljs-title">some</span> <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDays: [<span class="hljs-type">Day</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">HStack</span> {
            <span class="hljs-comment">// more code will go here.</span>
        }
    }
}
</code></pre>
<p>Inside the <code>HStack</code>, we need a <code>ForEach</code> to show all the options, for better user experience, we can use the first letter of the raw value of the <code>Day</code> options.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">DaysPicker</span>: <span class="hljs-title">some</span> <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDays: [<span class="hljs-type">Day</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">HStack</span> {
            <span class="hljs-type">ForEach</span>(<span class="hljs-type">Day</span>.allCases, id: \.<span class="hljs-keyword">self</span>) { day <span class="hljs-keyword">in</span>
                <span class="hljs-type">Text</span>(<span class="hljs-type">String</span>(day.rawValue.first!))
            }
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682479099799/2e97049a-b947-4f36-b091-06ec569ea69a.png" alt class="image--center mx-auto" /></p>
<p>Now we can style the text and remember to make the view modifiers conditional to indicate if a day is selected or not.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">DaysPicker</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDays: [<span class="hljs-type">Day</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">HStack</span> {
            <span class="hljs-type">ForEach</span>(<span class="hljs-type">Day</span>.allCases, id: \.<span class="hljs-keyword">self</span>) { day <span class="hljs-keyword">in</span>
                <span class="hljs-type">Text</span>(<span class="hljs-type">String</span>(day.rawValue.first!))
                    .bold()
                    .foregroundColor(.white)
                    .frame(width: <span class="hljs-number">30</span>, height: <span class="hljs-number">30</span>)
                    .background(selectedDays.<span class="hljs-built_in">contains</span>(day) ? <span class="hljs-type">Color</span>.cyan.cornerRadius(<span class="hljs-number">10</span>) : <span class="hljs-type">Color</span>.gray.cornerRadius(<span class="hljs-number">10</span>))
            }
        }
    }
}
</code></pre>
<p>In the example above, we added the <code>bold</code> modifier and a white foreground color and a frame for each text view. Then we used a ternary operator to check if the array <code>selectedDays</code> contains the specific item in the <code>ForEach</code> - if true, the background color is cyan and if false, the background color will be gray.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682479312171/b0e5fd54-adbf-4e1d-868d-6c97f286d982.png" alt class="image--center mx-auto" /></p>
<p>Finally, we can add an <code>onTapGesture</code> to update the state array <code>selectedDays</code> .</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">DaysPicker</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> selectedDays: [<span class="hljs-type">Day</span>] = []
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">HStack</span> {
            <span class="hljs-type">ForEach</span>(<span class="hljs-type">Day</span>.allCases, id: \.<span class="hljs-keyword">self</span>) { day <span class="hljs-keyword">in</span>
                <span class="hljs-type">Text</span>(<span class="hljs-type">String</span>(day.rawValue.first!))
                    .bold()
                    .foregroundColor(.white)
                    .frame(width: <span class="hljs-number">30</span>, height: <span class="hljs-number">30</span>)
                    .background(selectedDays.<span class="hljs-built_in">contains</span>(day) ? <span class="hljs-type">Color</span>.cyan.cornerRadius(<span class="hljs-number">10</span>) : <span class="hljs-type">Color</span>.gray.cornerRadius(<span class="hljs-number">10</span>))
                    .onTapGesture {
                        <span class="hljs-keyword">if</span> selectedDays.<span class="hljs-built_in">contains</span>(day) {
                            selectedDays.removeAll(<span class="hljs-keyword">where</span>: {$<span class="hljs-number">0</span> == day})
                        } <span class="hljs-keyword">else</span> {
                            selectedDays.append(day)
                        }
                    }
            }
        }
    }
}
</code></pre>
<p>In the example above, we added an <code>onTapGesture</code> modifier, in which we are checking if the day being processed by <code>ForEach</code> is there in the array, if yes, the code will remove it from the array, otherwise, the day will be added to the array.</p>
<p>Now you should be able to see the selected days having a cyan background.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1682479461274/652b8af2-c2b6-48fb-99d8-c6f0f6bf9dba.png" alt class="image--center mx-auto" /></p>
<p>In conclusion, SwiftUI makes it easy to implement a day of the week picker. By using an enum and the <code>Picker</code> view or <code>HStack</code>, we can create a simple and intuitive UI element that allows the user to select a day of the week with ease.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[Regex in SwiftUI]]></title><description><![CDATA[Using regular expressions (regex) can be a powerful tool in SwiftUI for validating user input and manipulating text. In this blog post, we’ll explore how to use regex in SwiftUI.
The code in this post is available here.
To use regex in SwiftUI, you f...]]></description><link>https://xavier7t.com/regex-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/regex-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[Regex]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Tue, 25 Apr 2023 03:00:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682391363668/1f66cdc0-3747-41f5-9e82-75337c4ed80f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Using regular expressions (regex) can be a powerful tool in SwiftUI for validating user input and manipulating text. In this blog post, we’ll explore how to use regex in SwiftUI.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/Regex">here</a>.</p>
<p>To use regex in SwiftUI, you first need to import the <code>Foundation</code> framework, which contains the <code>NSRegularExpression</code> class for working with regex. Here's an example of how to use regex to validate an email address in SwiftUI:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-keyword">import</span> Foundation

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> email: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> isEmailValid: <span class="hljs-type">Bool</span> = <span class="hljs-literal">false</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Enter email"</span>, text: $email)
                .textFieldStyle(<span class="hljs-type">RoundedBorderTextFieldStyle</span>())
                .padding()

            <span class="hljs-type">Text</span>(<span class="hljs-string">"Email is \(isEmailValid ? "</span>valid<span class="hljs-string">" : "</span>invalid<span class="hljs-string">")"</span>)
                .foregroundColor(isEmailValid ? .green : .red)
                .padding()

            <span class="hljs-type">Button</span>(<span class="hljs-string">"Validate email"</span>) {
                isEmailValid = isValidEmail(email)
            }
            .padding()
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isValidEmail</span><span class="hljs-params">(<span class="hljs-number">_</span> email: String)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">let</span> regex = <span class="hljs-keyword">try</span>! <span class="hljs-type">NSRegularExpression</span>(pattern: <span class="hljs-string">"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$"</span>, options: [.caseInsensitive])
        <span class="hljs-keyword">return</span> regex.firstMatch(<span class="hljs-keyword">in</span>: email, options: [], range: <span class="hljs-type">NSRange</span>(location: <span class="hljs-number">0</span>, length: email.utf16.<span class="hljs-built_in">count</span>)) != <span class="hljs-literal">nil</span>
    }
}
</code></pre>
<p>In the above code, we define a <code>TextField</code> for entering an email address, and a <code>Text</code> view that displays whether the email is valid or not. When the "Validate email" button is tapped, we call the <code>isValidEmail</code> function, which uses a regex pattern to validate the email address.</p>
<p>Let’s take a closer look at the regex value:</p>
<p><code>^[A-Z0-9._%+-]+</code> - The string being checked must start with one or more (<code>+</code>) of characters that’s a letter(<code>A-Z</code>), a number(<code>0-9</code>) or one of the following special characters (<code>.</code> <code>_</code> <code>%</code> <code>+</code> <code>-</code>).</p>
<p><code>@</code> - The string being checked must contain an "at" sign <code>@</code>, following the characters mentioned above.</p>
<p><code>[A-Z0-9.-]+</code> The string being checked must contain one or more letters(<code>A-Z</code>), numbers(<code>0-9</code>), a dot(<code>.</code>) or a hyphen(<code>-</code>), following the "at" sign(<code>@</code>).</p>
<p><code>\\.[A-Z]{2,}$</code> The string being checked must ends with(<code>$</code>) a dot(<code>.</code>) following by at least 2 (<code>{2,}</code>)characters of letters(<code>[A-Z]</code>).</p>
<p>For a better user experience, we can also replace the <code>Button</code> with a <code>onChange</code> view modifier so that the email will be checked against the regex whenever its value gets changed.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> SwiftUI
<span class="hljs-keyword">import</span> Foundation

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> email: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> isEmailValid: <span class="hljs-type">Bool</span> = <span class="hljs-literal">false</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Enter email"</span>, text: $email)
                .textFieldStyle(<span class="hljs-type">RoundedBorderTextFieldStyle</span>())
                .padding()

            <span class="hljs-type">Text</span>(<span class="hljs-string">"Email is \(isEmailValid ? "</span>valid<span class="hljs-string">" : "</span>invalid<span class="hljs-string">")"</span>)
                .foregroundColor(isEmailValid ? .green : .red)
                .padding()

<span class="hljs-comment">//            Button("Validate email") {</span>
<span class="hljs-comment">//                isEmailValid = isValidEmail(email)</span>
<span class="hljs-comment">//            }</span>
<span class="hljs-comment">//            .padding()</span>
                .onChange(of: email) { newValue <span class="hljs-keyword">in</span>
                    isEmailValid = isValidEmail(newValue)
                }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isValidEmail</span><span class="hljs-params">(<span class="hljs-number">_</span> email: String)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">let</span> regex = <span class="hljs-keyword">try</span>! <span class="hljs-type">NSRegularExpression</span>(pattern: <span class="hljs-string">"^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$"</span>, options: [.caseInsensitive])
        <span class="hljs-keyword">return</span> regex.firstMatch(<span class="hljs-keyword">in</span>: email, options: [], range: <span class="hljs-type">NSRange</span>(location: <span class="hljs-number">0</span>, length: email.utf16.<span class="hljs-built_in">count</span>)) != <span class="hljs-literal">nil</span>
    }
}
</code></pre>
<p>Here are a few more examples of how to use regex in SwiftUI:</p>
<ul>
<li>Masking a phone number:</li>
</ul>
<pre><code class="lang-swift">    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">maskAPhoneNumber</span><span class="hljs-params">(<span class="hljs-number">_</span> phoneNumber: String)</span></span> -&gt; <span class="hljs-type">String</span> {
        <span class="hljs-keyword">let</span> regex = <span class="hljs-keyword">try</span>! <span class="hljs-type">NSRegularExpression</span>(pattern: <span class="hljs-string">"^\\d{3}\\d{3}\\d{4}$"</span>, options: [])
        <span class="hljs-keyword">return</span> regex.stringByReplacingMatches(<span class="hljs-keyword">in</span>: phoneNumber, options: [], range: <span class="hljs-type">NSRange</span>(location: <span class="hljs-number">0</span>, length: phoneNumber.utf16.<span class="hljs-built_in">count</span>), withTemplate: <span class="hljs-string">"***-***-$3"</span>)
    }
</code></pre>
<ul>
<li>Extracting hashtags from a string:</li>
</ul>
<pre><code class="lang-swift">    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">extractHashtag</span><span class="hljs-params">(<span class="hljs-number">_</span> string: String)</span></span> -&gt; [<span class="hljs-type">String</span>] {
        <span class="hljs-keyword">let</span> regex = <span class="hljs-keyword">try</span>! <span class="hljs-type">NSRegularExpression</span>(pattern: <span class="hljs-string">"#\\w+"</span>, options: [])
        <span class="hljs-keyword">let</span> matches = regex.matches(<span class="hljs-keyword">in</span>: string, options: [], range: <span class="hljs-type">NSRange</span>(location: <span class="hljs-number">0</span>, length: string.utf16.<span class="hljs-built_in">count</span>))
        <span class="hljs-keyword">return</span> matches.<span class="hljs-built_in">map</span> { match <span class="hljs-keyword">in</span>
            (string <span class="hljs-keyword">as</span> <span class="hljs-type">NSString</span>).substring(with: match.range)
        }
    }
</code></pre>
<ul>
<li>Replacing all instances of a word in a string:</li>
</ul>
<pre><code class="lang-swift">    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">replace</span><span class="hljs-params">(<span class="hljs-number">_</span> old: String, with new: String, <span class="hljs-keyword">in</span> string: String)</span></span> -&gt; <span class="hljs-type">String</span> {
        <span class="hljs-keyword">let</span> regex = <span class="hljs-keyword">try</span>! <span class="hljs-type">NSRegularExpression</span>(pattern: <span class="hljs-string">"\\b\(old)\\b"</span>, options: [.caseInsensitive])
        <span class="hljs-keyword">return</span> regex.stringByReplacingMatches(<span class="hljs-keyword">in</span>: string, options: [], range: <span class="hljs-type">NSRange</span>(location: <span class="hljs-number">0</span>, length: string.utf16.<span class="hljs-built_in">count</span>), withTemplate: new)
    }
</code></pre>
<ul>
<li>Validating a password:</li>
</ul>
<pre><code class="lang-swift">    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">isValidPassword</span><span class="hljs-params">(<span class="hljs-number">_</span> password: String)</span></span> -&gt; <span class="hljs-type">Bool</span> {
        <span class="hljs-keyword">let</span> regex = <span class="hljs-keyword">try</span>! <span class="hljs-type">NSRegularExpression</span>(pattern: <span class="hljs-string">"^(?=.*[A-Z])(?=.*\\d)[A-Za-z\\d@$!%*?&amp;]{8,}$"</span>, options: [])
        <span class="hljs-keyword">return</span> regex.firstMatch(<span class="hljs-keyword">in</span>: password, options: [], range: <span class="hljs-type">NSRange</span>(location: <span class="hljs-number">0</span>, length: password.utf16.<span class="hljs-built_in">count</span>)) != <span class="hljs-literal">nil</span>
    }
</code></pre>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[onMove in SwiftUI List]]></title><description><![CDATA[SwiftUI provides a simple and elegant way to implement lists with the List view. But sometimes, we need to add some extra functionality to make our lists more interactive. One such functionality is "drag-and-drop" reordering of list items.
In this bl...]]></description><link>https://xavier7t.com/onmove-in-swiftui-list</link><guid isPermaLink="true">https://xavier7t.com/onmove-in-swiftui-list</guid><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iOS]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[list]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sat, 22 Apr 2023 04:08:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1682136328330/5a0e6c73-c9d8-4c64-94e0-911a59276456.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>SwiftUI provides a simple and elegant way to implement lists with the List view. But sometimes, we need to add some extra functionality to make our lists more interactive. One such functionality is "drag-and-drop" reordering of list items.</p>
<p>In this blog post, we will learn how to implement drag-and-drop reordering in a SwiftUI List using the onMove modifier. Let's get started!</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/List%20onMove">here</a>.</p>
<h1 id="heading-step-1-create-a-list-with-data">Step 1: Create a List with data</h1>
<p>First, let's create a simple list with some data. For this example, we will create a list of colors.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> colors = [<span class="hljs-string">"Red"</span>, <span class="hljs-string">"Green"</span>, <span class="hljs-string">"Blue"</span>, <span class="hljs-string">"Yellow"</span>, <span class="hljs-string">"Purple"</span>]

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">List</span> {
            <span class="hljs-type">ForEach</span>(colors, id: \.<span class="hljs-keyword">self</span>) { color <span class="hljs-keyword">in</span>
                <span class="hljs-type">Text</span>(color)
            }
        }
    }
}
</code></pre>
<h1 id="heading-step-2-add-onmove-modifier">Step 2: Add onMove modifier</h1>
<p>Now, we need to add the onMove modifier to the List view to enable drag and drop reordering. The onMove modifier is called when the user initiates a drag on a list item. We can then update the data source with the new order.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> colors = [<span class="hljs-string">"Red"</span>, <span class="hljs-string">"Green"</span>, <span class="hljs-string">"Blue"</span>, <span class="hljs-string">"Yellow"</span>, <span class="hljs-string">"Purple"</span>]

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">List</span> {
            <span class="hljs-type">ForEach</span>(colors, id: \.<span class="hljs-keyword">self</span>) { color <span class="hljs-keyword">in</span>
                <span class="hljs-type">Text</span>(color)
            }
            .onMove(perform: move)
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">move</span><span class="hljs-params">(from source: IndexSet, to destination: Int)</span></span> {
        colors.move(fromOffsets: source, toOffset: destination)
    }
}
</code></pre>
<h1 id="heading-step-3-add-reordering-handle">Step 3: Add reordering handle</h1>
<p>Finally, we can add a reordering handle to the list items to make it more clear to the user that the items can be reordered. We can use the move button provided by SwiftUI.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> colors = [<span class="hljs-string">"Red"</span>, <span class="hljs-string">"Green"</span>, <span class="hljs-string">"Blue"</span>, <span class="hljs-string">"Yellow"</span>, <span class="hljs-string">"Purple"</span>]

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">List</span> {
            <span class="hljs-type">ForEach</span>(colors, id: \.<span class="hljs-keyword">self</span>) { color <span class="hljs-keyword">in</span>
                <span class="hljs-type">Text</span>(color)
            }
            .onMove(perform: move)
        }
        .onAppear {
            <span class="hljs-type">UITableView</span>.appearance().isEditing = <span class="hljs-literal">true</span>
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">move</span><span class="hljs-params">(from source: IndexSet, to destination: Int)</span></span> {
        colors.move(fromOffsets: source, toOffset: destination)
    }
}
</code></pre>
<p>We also need to set the UITableView's <code>isEditing</code> property to true in order to enable the reordering handles.</p>
<p>And that's it! With just a few lines of code, we have added drag-and-drop reordering to our SwiftUI List.</p>
<p><strong>Note</strong>: If you find it difficult to drop the item while testing this functionality in the Preview Canvas, try to update the <code>.app</code> file by placing the ContentView inside it and drag-and-drop an item in the Xcode Simulator.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this blog post, we learned how to implement drag-and-drop reordering in a SwiftUI List using the onMove modifier. We also added a reordering handle to make it more clear to the user that the items can be reordered. SwiftUI provides a simple and elegant way to implement complex functionality like this, making it easy to create great user experiences.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[Integrating UIKit into SwiftUI]]></title><description><![CDATA[There may be times when you need to use some of the traditional UIKit controls in your SwiftUI app. Fortunately, SwiftUI allows you to integrate UIKit components into your app seamlessly. In this blog post, we'll explore how to integrate UIKit into S...]]></description><link>https://xavier7t.com/integrating-uikit-into-swiftui</link><guid isPermaLink="true">https://xavier7t.com/integrating-uikit-into-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[UIkit]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Thu, 20 Apr 2023 04:09:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681963730310/14d99100-92a6-4f68-8bc5-b7a25993aadf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There may be times when you need to use some of the traditional UIKit controls in your SwiftUI app. Fortunately, SwiftUI allows you to integrate UIKit components into your app seamlessly. In this blog post, we'll explore how to integrate UIKit into SwiftUI with some code examples.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/UIKit%20Integration">here</a>.</p>
<h2 id="heading-the-uikit-integration-in-swiftui"><strong>The UIKit Integration in SwiftUI</strong></h2>
<p>SwiftUI provides a way to integrate UIKit components into your app using the <code>UIViewRepresentable</code> protocol. This protocol allows you to create a SwiftUI view that wraps a UIKit view.</p>
<p>To use <code>UIViewRepresentable</code>, you need to create a struct that conforms to the protocol. This struct must implement two methods: <code>makeUIView(context:)</code> and <code>updateUIView(_:context:)</code>.</p>
<p>The <code>makeUIView(context:)</code> method is responsible for creating the UIKit view, while the <code>updateUIView(_:context:)</code> method updates the view with new data or properties.</p>
<p>Here's a basic example of how to create a <code>UIViewRepresentable</code> struct for a <code>UIActivityIndicatorView</code>:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ActivityIndicator</span>: <span class="hljs-title">UIViewRepresentable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeUIView</span><span class="hljs-params">(context: Context)</span></span> -&gt; <span class="hljs-type">UIActivityIndicatorView</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-type">UIActivityIndicatorView</span>(style: .large)
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateUIView</span><span class="hljs-params">(<span class="hljs-number">_</span> uiView: UIActivityIndicatorView, context: Context)</span></span> {
        uiView.startAnimating()
    }
}
</code></pre>
<p>In this example, we created a <code>UIActivityIndicatorView</code> and returned it from the <code>makeUIView(context:)</code> method. In the <code>updateUIView(_:context:)</code> method, we started animating the activity indicator.</p>
<h2 id="heading-using-the-uikit-component-in-swiftui"><strong>Using the UIKit Component in SwiftUI</strong></h2>
<p>To use the <code>UIViewRepresentable</code> struct in SwiftUI, you can simply add it as a view. Here's an example of how to add the <code>ActivityIndicator</code> view to a <code>VStack</code>:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">ActivityIndicator</span>()
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Loading..."</span>)
        }
    }
}
</code></pre>
<p>In this example, we added the <code>ActivityIndicator</code> view to a <code>VStack</code>, and then added a <code>Text</code> view below it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681962344161/8af24730-0493-4e5e-b772-616bbdb40180.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-wrapping-multiple-uikit-views-in-one-view"><strong>Wrapping Multiple UIKit Views in One View</strong></h2>
<p>You can also wrap multiple UIKit views in a single <code>UIViewRepresentable</code> struct. Here's an example of how to create a <code>UIStackView</code> and add two <code>UILabel</code> views to it:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">LabelStack</span>: <span class="hljs-title">UIViewRepresentable</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">makeUIView</span><span class="hljs-params">(context: Context)</span></span> -&gt; <span class="hljs-type">UIStackView</span> {
        <span class="hljs-keyword">let</span> stackView = <span class="hljs-type">UIStackView</span>()
        stackView.axis = .vertical
        stackView.alignment = .leading
        stackView.spacing = <span class="hljs-number">5</span>

        <span class="hljs-keyword">let</span> label1 = <span class="hljs-type">UILabel</span>()
        label1.text = <span class="hljs-string">"Label 1"</span>

        <span class="hljs-keyword">let</span> label2 = <span class="hljs-type">UILabel</span>()
        label2.text = <span class="hljs-string">"Label 2"</span>

        stackView.addArrangedSubview(label1)
        stackView.addArrangedSubview(label2)

        <span class="hljs-keyword">return</span> stackView
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateUIView</span><span class="hljs-params">(<span class="hljs-number">_</span> uiView: UIStackView, context: Context)</span></span> {
    }
}
</code></pre>
<p>In this example, we created a <code>UIStackView</code> and added two <code>UILabel</code> views to it. We then returned the <code>UIStackView</code> from the <code>makeUIView(context:)</code> method.</p>
<p>To use the <code>LabelStack</code> view in SwiftUI, we can simply add it to a <code>VStack</code> or any other SwiftUI container view.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681962409326/8bd44c5f-7037-4471-b929-5553ce4a82c7.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Integrating UIKit components into SwiftUI is a powerful technique that can give your app additional capabilities and flexibility. By using the <code>UIViewRepresentable</code> protocol, you can seamlessly integrate UIKit views into your SwiftUI app.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[Image Caching in SwiftUI]]></title><description><![CDATA[Caching images is an important technique for optimizing the performance of your SwiftUI app. When you load an image, it can take time to fetch it from a remote server or read it from disk. By caching the image, you can avoid repeating this time-consu...]]></description><link>https://xavier7t.com/image-caching-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/image-caching-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[ImageCaching]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Wed, 19 Apr 2023 04:37:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681878989504/2376208c-088a-4624-aba3-b680ca221571.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Caching images is an important technique for optimizing the performance of your SwiftUI app. When you load an image, it can take time to fetch it from a remote server or read it from disk. By caching the image, you can avoid repeating this time-consuming process every time the image is needed. In this blog post, we'll explore how to cache images in SwiftUI.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/Image%20Caching">here</a>.</p>
<h3 id="heading-using-image-cache"><strong>Using Image Cache</strong></h3>
<p>One way to cache images in SwiftUI is to create an <code>ImageCache</code> class. This class can store a cache of <code>UIImage</code> objects, and it can be accessed from any part of your app. Here's an example of how you can create an <code>ImageCache</code> class:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageCache</span> </span>{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> shared = <span class="hljs-type">ImageCache</span>()

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">let</span> cache = <span class="hljs-type">NSCache</span>&lt;<span class="hljs-type">NSString</span>, <span class="hljs-type">UIImage</span>&gt;()

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">init</span>() {}

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">set</span><span class="hljs-params">(<span class="hljs-number">_</span> image: UIImage, forKey key: String)</span></span> {
        cache.setObject(image, forKey: key <span class="hljs-keyword">as</span> <span class="hljs-type">NSString</span>)
    }

    <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">get</span><span class="hljs-params">(forKey key: String)</span></span> -&gt; <span class="hljs-type">UIImage?</span> {
        <span class="hljs-keyword">return</span> cache.object(forKey: key <span class="hljs-keyword">as</span> <span class="hljs-type">NSString</span>)
    }
}
</code></pre>
<p>In this example, we've created a singleton <code>ImageCache</code> object using the <code>shared</code> property. The <code>cache</code> property is an <code>NSCache</code> object that stores <code>UIImage</code> objects, and we've defined <code>set(_:,forKey:)</code> and <code>get(forKey:)</code> methods to add and retrieve images from the cache.</p>
<h3 id="heading-caching-images-with-url"><strong>Caching Images with URL</strong></h3>
<p>Another common use case for caching images in SwiftUI is when loading images from a remote server. In this case, you can use the <code>dataTask(with:completionHandler:)</code> method of the <code>URLSession</code> API to load the image data asynchronously. Once the image data is loaded, you can cache it using the <code>ImageCache</code> class.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">RemoteImage</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">ObservedObject</span> <span class="hljs-keyword">var</span> imageLoader: <span class="hljs-type">ImageLoader</span>

    <span class="hljs-keyword">init</span>(url: <span class="hljs-type">String</span>) {
        imageLoader = <span class="hljs-type">ImageLoader</span>(url: url)
    }

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> image = imageLoader.image {
            <span class="hljs-type">Image</span>(uiImage: image)
                .resizable()
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-type">ProgressView</span>()
        }
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ImageLoader</span>: <span class="hljs-title">ObservableObject</span> </span>{
    @<span class="hljs-type">Published</span> <span class="hljs-keyword">var</span> image: <span class="hljs-type">UIImage?</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> url: <span class="hljs-type">String</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> task: <span class="hljs-type">URLSessionDataTask?</span>

    <span class="hljs-keyword">init</span>(url: <span class="hljs-type">String</span>) {
        <span class="hljs-keyword">self</span>.url = url
        loadImage()
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadImage</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> cachedImage = <span class="hljs-type">ImageCache</span>.shared.<span class="hljs-keyword">get</span>(forKey: url) {
            <span class="hljs-keyword">self</span>.image = cachedImage
            <span class="hljs-keyword">return</span>
        }

        <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> url = <span class="hljs-type">URL</span>(string: url) <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }

        task = <span class="hljs-type">URLSession</span>.shared.dataTask(with: url) { data, response, error <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> data = data, error == <span class="hljs-literal">nil</span> <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }

            <span class="hljs-type">DispatchQueue</span>.main.async {
                <span class="hljs-keyword">let</span> image = <span class="hljs-type">UIImage</span>(data: data)
                <span class="hljs-keyword">self</span>.image = image
                <span class="hljs-type">ImageCache</span>.shared.<span class="hljs-keyword">set</span>(image!, forKey: <span class="hljs-keyword">self</span>.url)
            }
        }
        task?.resume()
    }
}
</code></pre>
<p>In this example, we've created a <code>RemoteImage</code> view that loads an image from a remote server using the <code>ImageLoader</code> class. The <code>ImageLoader</code> class is an <code>ObservableObject</code> that uses the <code>dataTask(with:completionHandler:)</code> method to load the image data asynchronously. We've also added a check for cached images using the <code>ImageCache</code> class, which avoids fetching the image from the remote server if it's already cached.</p>
<p>Note: To validate the implementation above, you can use the image from the project iOSDevX with the URL: "<a target="_blank" href="https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/Assets.xcassets/demo.imageset/demo.png?raw=true">https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/Assets.xcassets/demo.imageset/demo.png?raw=true</a>". You can write a simple SwiftUI View like the one below:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    <span class="hljs-keyword">let</span> urlString = <span class="hljs-string">"https://github.com/xavier7t/iOSDevX/blob/main/iOSDevX/Assets.xcassets/demo.imageset/demo.png?raw=true"</span>
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">RemoteImage</span>(url: urlString)
                .frame(width: <span class="hljs-number">150</span>, height: <span class="hljs-number">150</span>, alignment: .center)
                .cornerRadius(<span class="hljs-number">10</span>)
        }
    }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681877607129/461dd138-5a55-4302-9c8b-8c22441c1f1d.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-conclusion"><strong>Conclusion</strong></h1>
<p>Caching images is an important technique for optimizing the performance of your SwiftUI app. By creating an <code>ImageCache</code> class and using it to cache images, you can avoid repeating time-consuming image-loading operations.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[withAnimation in SwiftUI]]></title><description><![CDATA[Animations are an important part of modern app development. They can make your app more engaging, intuitive, and fun to use. SwiftUI, Apple's new declarative UI framework, provides a range of powerful tools for creating fluid and dynamic animations. ...]]></description><link>https://xavier7t.com/withanimation-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/withanimation-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[withAnimation]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Tue, 18 Apr 2023 05:03:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681794205781/397be253-6edd-43c7-a864-081d8c274630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Animations are an important part of modern app development. They can make your app more engaging, intuitive, and fun to use. SwiftUI, Apple's new declarative UI framework, provides a range of powerful tools for creating fluid and dynamic animations. In this blog post, we'll explore how SwiftUI <code>withAnimation</code> work and how you can use it in your own projects.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/withAnimation">here</a>.</p>
<h3 id="heading-the-basics-of-withanimation"><strong>The basics of withAnimation</strong></h3>
<p>In SwiftUI, <code>withAnimation</code> is a function that takes a closure that contains the changes you want to animate. The closure can contain any kind of view manipulation, such as changing the position or opacity of a view.</p>
<p>Here's a simple example that shows how to animate a button when it's tapped:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> scale: <span class="hljs-type">CGFloat</span> = <span class="hljs-number">1.0</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">Button</span>(<span class="hljs-string">"Tap me to enlarge!"</span>) {
            withAnimation {
                <span class="hljs-keyword">self</span>.scale *= <span class="hljs-number">1.5</span>
            }
        }
        .scaleEffect(scale)
    }
}
</code></pre>
<p>In this example, we first declare a state property called <code>scale</code>, which is used to control the size of the button. When the button is tapped, we use <code>withAnimation</code> to animate the <code>scale</code> property. The <code>scaleEffect</code> modifier is then used to apply the scale factor to the button.</p>
<p>Compare the following three screenshots to see the animation:</p>
<p>1-Original</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681793341585/80519d6f-31f5-4ce4-baee-786add831aed.png" alt class="image--center mx-auto" /></p>
<p>2-Tapped once</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681793349510/1f4187f6-0c9e-4f46-820e-2a5d5ad0fb1c.png" alt class="image--center mx-auto" /></p>
<p>3-Tapped twice</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681793357643/a820891e-4167-43e2-b4cc-a9ae3d478909.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-animating-view-transitions"><strong>Animating view transitions</strong></h3>
<p>One of the most common uses of animations in app development is to animate transitions between views. SwiftUI makes this task incredibly easy with its built-in support for view transitions.</p>
<p>To animate a view transition in SwiftUI, you simply need to use one of the built-in transition modifiers. There are several different transition modifiers to choose from, such as <code>opacity</code>, <code>move</code>, and <code>scale</code>.</p>
<p>Here's an example that shows how to animate a transition between two views:</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView2</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> showDetails = <span class="hljs-literal">false</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">Button</span>((showDetails ? <span class="hljs-string">"Hide"</span> : <span class="hljs-string">"Show"</span>) + <span class="hljs-string">" details"</span>) {
                withAnimation {
                    <span class="hljs-keyword">self</span>.showDetails.toggle()
                }
            }
            <span class="hljs-keyword">if</span> showDetails {
                <span class="hljs-type">Text</span>(<span class="hljs-string">"Here are some details"</span>)
                    .transition(.opacity)
            }
        }
    }
}
</code></pre>
<p>In this example, we use the <code>showDetails</code> state property to control whether the details view is shown or hidden. When the "Show details" button is tapped, we use <code>withAnimation</code> to animate the <code>showDetails</code> property. The details view is then shown or hidden using the <code>if</code> statement.</p>
<p>The <code>transition</code> modifier is used to animate the opacity of the details view. When the view appears or disappears, it fades in or out.</p>
<ol>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681793651160/8eef294f-268a-420b-9eeb-7aa1eb4bea11.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1681793665789/4389fbe0-0438-4c13-94fe-d567b80b9a76.png" alt class="image--center mx-auto" /></p>
</li>
</ol>
<p>You can also replace the transition value <code>.opacity</code> to <code>.scale</code>, <code>.slide</code> or <code>.identity</code> to feel the different types of transition in the preview or the simulator.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Animations are an essential part of modern app development, and SwiftUI makes it easy to create fluid and dynamic animations. In this blog post, we've explored some of the basics of SwiftUI animations and how to use them to create engaging and intuitive user interfaces.</p>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item><item><title><![CDATA[CryptoKit in SwiftUI]]></title><description><![CDATA[Security is a crucial aspect of mobile app development. In iOS app development, encrypting user passwords is an important step to ensure the protection of user data. In this blog post, we'll show you how to encrypt passwords in SwiftUI.
The code in t...]]></description><link>https://xavier7t.com/cryptokit-in-swiftui</link><guid isPermaLink="true">https://xavier7t.com/cryptokit-in-swiftui</guid><category><![CDATA[iOS]]></category><category><![CDATA[Swift]]></category><category><![CDATA[SwiftUI]]></category><category><![CDATA[iosdevx]]></category><category><![CDATA[cryptokit]]></category><dc:creator><![CDATA[Xavier]]></dc:creator><pubDate>Sat, 15 Apr 2023 16:28:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1681575964040/7c1f958b-38f6-4349-9fb9-f22bd7ab8824.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Security is a crucial aspect of mobile app development. In iOS app development, encrypting user passwords is an important step to ensure the protection of user data. In this blog post, we'll show you how to encrypt passwords in SwiftUI.</p>
<p>The code in this post is available <a target="_blank" href="https://github.com/xavier7t/iOSDevX/tree/main/iOSDevX/202304-Apr%202023/CryptoKit">here</a>.</p>
<h2 id="heading-why-encrypt-passwords"><strong>Why Encrypt Passwords?</strong></h2>
<p>Encrypting passwords is essential because it ensures that the user's sensitive data remains safe in case of a security breach. When a user creates an account in your app, they typically choose a password that they can remember easily. However, if that password is not encrypted, it can be easily stolen by malicious actors. Encrypting the password makes it much more difficult for attackers to obtain and use.</p>
<h2 id="heading-choosing-an-encryption-algorithm"><strong>Choosing an Encryption Algorithm</strong></h2>
<p>There are many encryption algorithms available, but not all of them are suitable for password encryption. A common algorithm used for password encryption is bcrypt. Bcrypt is a slow hashing algorithm that is designed specifically for password storage. It is computationally expensive, which makes brute-force attacks much more difficult.</p>
<p>SwiftUI does not have built-in support for bcrypt, but there are libraries available that make it easy to use. One popular library is called <code>CryptoKit</code>.</p>
<h2 id="heading-using-cryptokit-to-encrypt-passwords"><strong>Using CryptoKit to Encrypt Passwords</strong></h2>
<p>To use <code>CryptoKit</code> to encrypt passwords, we'll start by importing the library in our Swift file:</p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> CryptoKit
</code></pre>
<p>Next, we'll create a function that will take a password string as input and return an encrypted password string:</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">encryptPassword</span><span class="hljs-params">(password: String)</span></span> -&gt; <span class="hljs-type">String</span> {
    <span class="hljs-keyword">let</span> salt = <span class="hljs-string">"mysalt"</span>
    <span class="hljs-keyword">let</span> saltedPassword = password + salt

    <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> saltedPasswordData = saltedPassword.data(using: .utf8) <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>
    }

    <span class="hljs-keyword">let</span> hashedPassword = <span class="hljs-type">SHA256</span>.hash(data: saltedPasswordData)
    <span class="hljs-keyword">let</span> hashedPasswordString = hashedPassword.<span class="hljs-built_in">compactMap</span> { <span class="hljs-type">String</span>(format: <span class="hljs-string">"%02x"</span>, $<span class="hljs-number">0</span>) }.joined()

    <span class="hljs-keyword">return</span> hashedPasswordString
}
</code></pre>
<p>In this code, we're using the <code>SHA256</code> hashing function from <code>CryptoKit</code> to hash the salted password string. We're then converting the hashed data to a hexadecimal string and returning it.</p>
<p>Note that we're using a salt value to increase the security of our password encryption. The salt value is a random string that is added to the password before it is hashed. This makes it much more difficult for attackers to crack passwords using precomputed hash tables.</p>
<h2 id="heading-using-the-encrypt-password-function-in-swiftui"><strong>Using the Encrypt Password Function in SwiftUI</strong></h2>
<p>Now that we have our <code>encryptPassword</code> function, we can use it in our SwiftUI views. Let's create a simple view with a text field for the user to enter their password, and a button to encrypt the password.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> password: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> encryptedPassword: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Password"</span>, text: $password)

            <span class="hljs-type">Button</span>(<span class="hljs-string">"Encrypt Password"</span>) {
                encryptedPassword = encryptPassword(password: password)
            }

            <span class="hljs-type">Text</span>(<span class="hljs-string">"Encrypted Password: \(encryptedPassword)"</span>)
        }
    }
}
</code></pre>
<p>In this code, we're using the <code>@State</code> property wrapper to create two state variables: <code>password</code> and <code>encryptedPassword</code>. We're creating a text field for the user to enter their password, and a button to encrypt the password using our <code>encryptPassword</code> function. We're then displaying the encrypted password in a <code>Text</code> view.</p>
<h2 id="heading-redaction">Redaction</h2>
<p>After implementing the encryption functionalities, we can improve our logic by adding a button to hide the encrypted password with redaction. For more about Redaction, check my previous post <a target="_blank" href="https://xavier7t.com/redaction-in-swiftui">here</a>.</p>
<pre><code class="lang-swift"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentView</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> password: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> encryptedPassword: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> hideEncryptedPassword: <span class="hljs-type">Bool</span> = <span class="hljs-literal">false</span>

    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Password"</span>, text: $password)

            <span class="hljs-type">Button</span>(<span class="hljs-string">"Encrypt Password"</span>) {
                encryptedPassword = encryptPassword(password: password)
            }

            <span class="hljs-type">Text</span>(<span class="hljs-string">"Encrypted Password:"</span>)
                .bold()
            <span class="hljs-type">Group</span> {
                <span class="hljs-keyword">if</span> hideEncryptedPassword {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"\(encryptedPassword)"</span>)
                        .redacted(reason: .placeholder)
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"\(encryptedPassword)"</span>)
                }
            }
            <span class="hljs-type">Button</span>(hideEncryptedPassword ? <span class="hljs-string">"Show"</span> : <span class="hljs-string">"Hide"</span>) {
                hideEncryptedPassword.toggle()
            }
        }
    }
}
</code></pre>
<p>In the example above, we added a <code>@State</code> property of type <code>Bool</code> to indicate if the encrypted password text is hidden. Then we replaced the encrypted password text with a <code>Group</code> which is conditional to redact the text if <code>hideEncryptedPassword</code> is <code>true</code>. And we added another button to toggle the boolean value of <code>hideEncryptedPassword</code>.</p>
<h2 id="heading-ui-enhancement"><strong>UI Enhancement</strong></h2>
<p>And finally, we can make some UI Enhancement by adding borders, frames, bolding and / or colors to our text field and buttons.</p>
<pre><code class="lang-swift">
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">ContentViewEnhanced</span>: <span class="hljs-title">View</span> </span>{
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> password: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> encryptedPassword: <span class="hljs-type">String</span> = <span class="hljs-string">""</span>
    @<span class="hljs-type">State</span> <span class="hljs-keyword">var</span> hideEncryptedPassword: <span class="hljs-type">Bool</span> = <span class="hljs-literal">false</span>
    <span class="hljs-keyword">var</span> body: some <span class="hljs-type">View</span> {
        <span class="hljs-type">VStack</span> {
            <span class="hljs-type">TextField</span>(<span class="hljs-string">"Password"</span>, text: $password)
                .frame(width: <span class="hljs-number">200</span>, height: <span class="hljs-number">40</span>, alignment: .center)
                .border(.black)
            <span class="hljs-type">Button</span>(<span class="hljs-string">"Encrypt"</span>) {
                encryptedPassword = encryptPassword(password: password)
            }
            .bold()
            .foregroundColor(.white)
            .frame(width: <span class="hljs-number">200</span>, height: <span class="hljs-number">40</span>, alignment: .center)
            .background(<span class="hljs-type">Color</span>.blue.cornerRadius(<span class="hljs-number">10</span>))
            <span class="hljs-type">Text</span>(<span class="hljs-string">"Encrypted Password:"</span>)
                .bold()
            <span class="hljs-type">Group</span> {
                <span class="hljs-keyword">if</span> hideEncryptedPassword {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"\(encryptedPassword)"</span>)
                        .redacted(reason: .placeholder)
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-type">Text</span>(<span class="hljs-string">"\(encryptedPassword)"</span>)
                }
            }
            <span class="hljs-type">Button</span>(hideEncryptedPassword ? <span class="hljs-string">"Show"</span> : <span class="hljs-string">"Hide"</span>) {
                hideEncryptedPassword.toggle()
            }
            .bold()
            .foregroundColor(.white)
            .frame(width: <span class="hljs-number">200</span>, height: <span class="hljs-number">40</span>, alignment: .center)
            .background(<span class="hljs-type">Color</span>.blue.cornerRadius(<span class="hljs-number">10</span>))
        }
        .padding(.horizontal)
    }
}
</code></pre>
<p>And that’s all of today’s post. I hope it helps and let me know if it is by leaving a comment. Don’t forget to subscribe to my newsletter if you’d like to receive posts like this via email.</p>
<p>I’ll see you in the next post!</p>
]]></content:encoded></item></channel></rss>