{"@attributes":{"version":"2.0"},"channel":{"title":"Hello! Kamil","link":"https:\/\/kamil.id\/","description":{},"language":"en","lastBuildDate":"Sun, 04 Jan 2026 17:52:37 +0100","item":[{"title":"2025 Reading Goals review \ud83d\udcda","link":"https:\/\/kamil.id\/2026\/01\/04\/reading-goals-review\/","pubDate":"Sun, 04 Jan 2026 17:52:37 +0100","guid":"http:\/\/kamil.micro.blog\/2026\/01\/04\/reading-goals-review\/","description":"<p>Last year, I shared my <a href=\"https:\/\/kamil.id\/2025\/01\/01\/reading-goals-for\/\">2025 Reading Goals<\/a>. My plans didn&rsquo;t go well. I tackle one-third of the books from the list. But I still achieved my reading goals. According to Goodreads, I read (or listened to) 26 books, which is two more than I planned.<\/p>\n<p>In this article, I&rsquo;ll list them all with short, one- or two-sentence reviews.<\/p>\n<ul>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/41881472-the-psychology-of-money\">The Psychology of Money<\/a> by Morgan Housel. This book is considered a 101 for anyone interested in finances or investing. The rules mentioned are usually basic, but I like the books when someone confirms what I already notice.<\/li>\n<li>Remembrance of Earth\u2019s Past #3: <a href=\"https:\/\/www.goodreads.com\/book\/show\/25451264-death-s-end\">Death\u2019s End<\/a> by Cixin Liu. Great ending of the modern cult-classic Sci-Fi trilogy. I didn&rsquo;t like The Three-Body Problem, but The Dark Forest and Death&rsquo;s End were excellent.<\/li>\n<li>Expeditionary Force #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/36449535-columbus-day\">Columbus Day<\/a> by Craig Alanson. I&rsquo;m glad I read this book before Bobiverse #3: Heaven&rsquo;s River, because it gives me important references. Very enjoyable sci-fi about space\/aliens from a soldier&rsquo;s perspective.<\/li>\n<li>Hyperion Cantos #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/77566.Hyperion\">Hyperion<\/a> by Dan Simmons. Hyperion is considered a classic of Science Fiction. But I had a problem with that book. It is a set of &ldquo;connected&rdquo; stories, which is not bad in itself, but the main storyline ends in a cliffhanger.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/13079982-fahrenheit-451\">Fahrenheit 451<\/a> by Ray Bradbury. Short dystopian book. Must read in my opinion. I listened to it as a great full-cast interpretation.<\/li>\n<li>Diddly Squat #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/56669595-diddly-squat\">Diddly Squat: A Year on the Farm<\/a> by Jeremy Clarkson. Clarkson&rsquo;s Farm is wholesome content. Diddly Squat Books is a collection of Jeremy&rsquo;s farm articles. Nothing revolutionary, but if you need more Clarkson&rsquo;s Farm between the seasons, this one is for you.<\/li>\n<li>Bobiverse #3: <a href=\"https:\/\/www.goodreads.com\/book\/show\/35506021-all-these-worlds\">All These Worlds<\/a> by Dennis E. Taylor. I already said that in my reading goals article, but I will repeat: Bobiverse is awesome! All These Worlds is a great conclusion of an epic story arc. Now I&rsquo;m reading the next book - Heaven&rsquo;s River.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/540020.The_Day_of_the_Jackal\">The Day of the Jackal<\/a> by Frederick Forsyth. I learned a new term - competency porn. I plan to write an article about this, but in short, it is a term for fiction that portrays exceptionally capable protagonists tackling difficult tasks with great proficiency. I probably like that genre. The Day of the Jackal is a great example of it (except that Jackal is an antagonist).<\/li>\n<li>(Polish only) <a href=\"https:\/\/www.goodreads.com\/book\/show\/25314955-reputacja\">Reputacja<\/a> by Andrzej Pilipiuk. Short fantasy stories from a Polish author. I&rsquo;m re-reading all the books from the series.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/54555315-silent-hill-2\">Boss Fight Books #27: Silent Hill 2<\/a> by Mike Drucker. I planned to make a video about the Silent Hill 2 video game. The video didn&rsquo;t happen, but I read a short book about the game&rsquo;s history. It contains a lot of details, and I feel it is a great analysis of the game.<\/li>\n<li>Hyperion Cantos #2: <a href=\"https:\/\/www.goodreads.com\/book\/show\/77565.The_Fall_of_Hyperion\">The Fall of Hyperion<\/a> by Dan Simmons. I mentioned a cliffhanger in the Hyperion book. To find out how the story ends, I listened to The Fall of Hyperion. I was already familiar with characters, and this book was better for me.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/38820046-21-lessons-for-the-21st-century\">21 Lessons for the 21st Century<\/a> by Yuval Noah Harari. Harari&rsquo;s books are always worth reading. This one tackles hot topics like AI, so it is even more relevant now.<\/li>\n<li>Helliconia #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/672244.Helliconia_Spring\">Helliconia Spring<\/a> by Brian W. Aldiss. This is probably the worst book I read this year. For me, it was boring. The author created a vivid and complex world, but I wasn&rsquo;t able to connect with any of the characters.<\/li>\n<li>(Polish only) <a href=\"https:\/\/www.goodreads.com\/book\/show\/55289532-finansowa-forteca\">Finansowa Forteca<\/a> by Marcin Iwu\u0107. Excellent book about personal finances. I&rsquo;ll recommend it to anybody who wants to organize home finances.<\/li>\n<li>Dungeon Crawler Carl #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/54659324-dungeon-crawler-carl\">Dungeon Crawler Carl<\/a> by Matt Dinniman. This was my favorite read this year. I had a great laugh and couldn&rsquo;t put this book down until the end. I&rsquo;m happy that there is a lot more to discover in Carl and Princess Donut&rsquo;s adventures.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/18373.Flowers_for_Algernon\">Flowers for Algernon<\/a> by Daniel Keyes. Fascinating story about a man who gains super intelligence.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/216670080-strange-pictures\">Strange Pictures<\/a> by Uketsu. It was highly advertised on social media, so I picked this up. The book is strange and mysterious. It was an enjoyable read, but I had a feeling that the writing quality was not high.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/9014.The_Long_Walk\">The Long Walk<\/a> by Richard Bachman. I never heard of this King&rsquo;s book before the movie. I am probably a bit too old to feel connected with young characters. But still, I didn&rsquo;t regret reading it.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/9990585-starship-troopers\">Starship Troopers<\/a> by Robert A. Heinlein. I really like the Starship Troopers movie, so I wanted to get familiar with the classic original. It turns out that a movie and a book are not so similar. For me, the movie was better, but since it is a classic book, I&rsquo;m not mad that I read it.<\/li>\n<li>The Illuminae Files #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/23395680-illuminae\">Illuminae<\/a> by Amie Kaufman. This was another book (after The Long Walk) aimed at a younger audience. The book has an interesting form (it is a set of documents, chat logs, etc.), but the story is somehow dull. I won&rsquo;t be reading the next books in this series. If you want to experience a book that plays with form, I recommend <a href=\"https:\/\/www.goodreads.com\/book\/show\/24800.House_of_Leaves\">House of Leaves<\/a> by Mark Z. Danielewski.<\/li>\n<li>Harry Potter #1: <a href=\"https:\/\/www.goodreads.com\/book\/show\/3.Harry_Potter_and_the_Sorcerer_s_Stone\">Harry Potter and the Sorcerer\u2019s Stone<\/a> by J.K. Rowling. I&rsquo;m listening to Harry Potter as a great <a href=\"https:\/\/www.audible.com\/pd\/Harry-Potter-and-the-Philosophers-Stone-Full-Cast-Edition-Audiobook\/B0F14XST77?source_code=ASSGB149080119000H&amp;share_location=pdp\">full-cast edition<\/a> on Audible.<\/li>\n<li>Harry Potter #2: <a href=\"https:\/\/www.goodreads.com\/book\/show\/15881.Harry_Potter_and_the_Chamber_of_Secrets\">Harry Potter and the Chamber of Secrets<\/a> by J.K. Rowling. I&rsquo;m listening to Harry Potter as a great <a href=\"https:\/\/www.audible.com\/pd\/Harry-Potter-and-the-Chamber-of-Secrets-Full-Cast-Edition-Audiobook\/B0F1553GZJ?source_code=ASSGB149080119000H&amp;share_location=pdp\">full-cast edition<\/a> on Audible.<\/li>\n<li>Robot #4: <a href=\"https:\/\/www.goodreads.com\/book\/show\/76688.Robots_and_Empire\">Robots and Empire<\/a> by Isaac Asimov. My only Asimov book I read this year. I finished the Robot series. Now I will continue to the Galactic Empire.<\/li>\n<li>(Polish only) <a href=\"https:\/\/www.goodreads.com\/book\/show\/29956607-litr-ciek-ego-o-owiu\">Litr ciek\u0142ego o\u0142owiu<\/a> by Andrzej Pilipiuk. Short fantasy stories from a Polish author. I&rsquo;m re-reading all the books from the series.<\/li>\n<li>Canonical Alien trilogy #3: <a href=\"https:\/\/www.goodreads.com\/book\/show\/21432866-alien\">Alien: River of Pain<\/a> by Christopher Golden. The book explains what happened between the Alien and Aliens movies. I listened to it on Audible, but I had a feeling it was a cast recording, so I&rsquo;ll have to reread it as a book.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/222376917-merry-murdle\">Merry Murdle<\/a> by G.T. Karber. The advent calendar of Murdle mysteries. Condensed form works better for me than the normal Murldle book (that I still have to finish).<\/li>\n<\/ul>\n"},{"title":"Reading Goals for 2025 \ud83d\udcda","link":"https:\/\/kamil.id\/2025\/01\/01\/reading-goals-for\/","pubDate":"Wed, 01 Jan 2025 23:18:17 +0100","guid":"http:\/\/kamil.micro.blog\/2025\/01\/01\/reading-goals-for\/","description":"<p>At the beginning of each year, I plan the books I want to read. This year, I decided to share my list publicly.<\/p>\n<p>Few rules:<\/p>\n<ul>\n<li>The following list is not comprehensive.<\/li>\n<li>I usually read around 30 books yearly, but like leaving room for spontaneity.<\/li>\n<li>The list also doesn&rsquo;t include comic books\/graphic novels since I usually don&rsquo;t treat them like books (reading a graphic novel usually takes only 2 to 3 hours).<\/li>\n<li>The list is not in reading order.<\/li>\n<li>I&rsquo;m mostly reading sci-fi and horror, so if you are not interested in that topic, you probably won&rsquo;t find anything interesting.<\/li>\n<\/ul>\n<p>Since everything is clear now, let&rsquo;s proceed with the list:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/394535.Blood_Meridian_or_the_Evening_Redness_in_the_West\">Blood Meridian, or, the Evening Redness in the West<\/a> by Cormac McCarthy. Right now, I&rsquo;m reading <a href=\"https:\/\/www.goodreads.com\/book\/show\/6288.The_Road\">The Road<\/a>, and it is a quality read, so I want to get familiar with more works of this author.<\/li>\n<li>Bobiverse Vol. 3: <a href=\"https:\/\/www.goodreads.com\/book\/show\/35506021-all-these-worlds\">All These Worlds<\/a> and Vol. 4: <a href=\"https:\/\/www.goodreads.com\/book\/show\/42950440-heaven-s-river\">\nHeaven&rsquo;s River<\/a> by Dennis E. Taylor. Bobiverse is my best find of 2023. Light-hearted, funny Sci-Fi for nerds.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/56614951-falling\">Falling<\/a> by T.J. Newman. I don&rsquo;t know much about this book, but I liked the premise, and the ebook was on sale.<\/li>\n<li>Alien novels, including <a href=\"https:\/\/www.goodreads.com\/book\/show\/36475917-alien\">Alien: The Cold Forge<\/a> by Alex White. I generally have 5 other Alien novels to read. I&rsquo;ll pick some of them this year. I&rsquo;m a big Alien franchise fan, and I try to watch, read, and play as much as possible.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/17404078-the-disaster-artist\">The Disaster Artist: My Life Inside The Room, the Greatest Bad Movie Ever Made<\/a> by Greg Sestero and Tom Bissell. A few years ago, I watched The Room and The Disaster Artist movies, and I like to read more about Tommy Wiseau&rsquo;s life.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/9990585-starship-troopers\">Starship Troopers<\/a> by Robert A. Heinlein. The Gold era of Sci-Fi. I enjoyed a movie based on that book, so I want to check the\noriginal.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/182733784-nuclear-war\">Nuclear War: A Scenario<\/a> by Annie Jacobsen. I always try to pick some nonfiction to read. This book was recommended by my friend.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/36449535-columbus-day\">Expeditionary Force #1: Columbus Day<\/a> by Craig Alanson. I started to listen to an audiobook last year but couldn&rsquo;t focus on it in that form, so I decided to switch to an ebook.<\/li>\n<li><a href=\"https:\/\/www.goodreads.com\/book\/show\/56075874-the-devil-s-advocate\">The Devil&rsquo;s Advocate<\/a> by Steve Cavanagh. Last year, I listened to Th1rt3en from this series, and it kept me on edge, so I selected another Eddie Flynn adventure.<\/li>\n<\/ul>\n"},{"title":"How to add keyboard toolbar actions in SwiftUI","link":"https:\/\/kamil.id\/2021\/09\/11\/how-to-add-keyboard-toolbar\/","pubDate":"Sat, 11 Sep 2021 13:06:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/09\/11\/how-to-add-keyboard-toolbar\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-add-keyboard-toolbar-actions-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to add keyboard toolbar actions in SwiftUI\">\n<p>SwiftUI contains a clever mechanism for adding toolbar actions. With one view modifier - <code>toolbar<\/code>, we can control toolbar items in different places of the application. It doesn&rsquo;t matter that you want to add a toolbar to the macOS navigation bar, iOS navigation bar, or iOS bottom bar; you will always start with .<code>toolbar { }<\/code>.<\/p>\n<p>SwiftUI 3 brings additional, longly awaited functionality - the possibility to displays toolbar actions above the system keyboard. You probably expect that already, but adding views to the keyboard toolbar is also very easy. Let&rsquo;s take a look at a provided example.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/keyboard-toolbar-screenshot.png\" width=\"277\" height=\"600\" alt=\"Toolbar over keyboard in SwiftUI\">\n<p>To show this functionality, I created a small project with the TextEditor and three keyboard actions - two of them put ASCI emojis in TextEditor, and the third one hides the keyboard.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text = <span style=\"color:#e6db74\">&#34;&#34;<\/span>\n    @FocusState <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> focus: Bool\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        TextEditor(text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n            .focused(<span style=\"color:#960050;background-color:#1e0010\">$<\/span>focus)\n            .frame(height: <span style=\"color:#ae81ff\">150<\/span>)\n            .padding()\n            .overlay(\n                RoundedRectangle(cornerRadius: <span style=\"color:#ae81ff\">8<\/span>)\n                    .stroke(Color.primary, lineWidth: <span style=\"color:#ae81ff\">1<\/span>)\n            )\n            .padding()\n    }\n}\n<\/code><\/pre><\/div><p>Code above displays <code>TextEditor<\/code> with some basic styling for better visibility. I also added the <code>@FocusState<\/code> property wrapper, which helps programmatically displaying and hiding the keyboard. The <code>@FocusState<\/code> is also a new addition in SwiftUI 3, but I&rsquo;ll prepare a separate article about it.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">.toolbar {\n    ToolbarItemGroup(placement: .keyboard) {\n        Button(<span style=\"color:#e6db74\">&#34;Shrug&#34;<\/span>) { text <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#e6db74\">&#34;<\/span><span style=\"color:#ae81ff\">\\n<\/span><span style=\"color:#e6db74\">\u00af<\/span><span style=\"color:#ae81ff\">\\\\<\/span><span style=\"color:#e6db74\">_(\u30c4)_\/\u00af&#34;<\/span> }\n        Button(<span style=\"color:#e6db74\">&#34;Flip&#34;<\/span>) { text <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#e6db74\">&#34;<\/span><span style=\"color:#ae81ff\">\\n<\/span><span style=\"color:#e6db74\">(\u256f\u00b0\u25a1\u00b0\uff09\u256f\ufe35 \u253b\u2501\u253b&#34;<\/span> }\n        Spacer()\n        Button(<span style=\"color:#e6db74\">&#34;Hide&#34;<\/span>) { focus = <span style=\"color:#66d9ef\">false<\/span> }\n    }\n}\n<\/code><\/pre><\/div><p>I told you it would be simple. In the content of the <code>toolbar<\/code> view modifier, you have to put <code>ToolbarItemGroup<\/code> view with placement parameter set to keyboard. You can place any View in the content ViewBuilder of <code>ToolbarItemGroup<\/code>. Usually, you will want to use <code>Buttons<\/code> and <code>Spacers<\/code> to align them properly.<\/p>\n<p>The first two buttons modify text property by adding correct ASCI characters; the third sets focus property to false. Calling this will hide the keyboard if it&rsquo;s visible.<\/p>\n<p>Below you can find the complete code of this experiment and a link to the Xcode project.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">SwiftUI<\/span>\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text = <span style=\"color:#e6db74\">&#34;&#34;<\/span>\n    @FocusState <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> focus: Bool\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        TextEditor(text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n            .focused(<span style=\"color:#960050;background-color:#1e0010\">$<\/span>focus)\n            .frame(height: <span style=\"color:#ae81ff\">150<\/span>)\n            .padding()\n            .overlay(\n                RoundedRectangle(cornerRadius: <span style=\"color:#ae81ff\">8<\/span>)\n                    .stroke(Color.primary, lineWidth: <span style=\"color:#ae81ff\">1<\/span>)\n            )\n            .padding()\n            .toolbar {\n                ToolbarItemGroup(placement: .keyboard) {\n                    Button(<span style=\"color:#e6db74\">&#34;Shrug&#34;<\/span>) { text <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#e6db74\">&#34;<\/span><span style=\"color:#ae81ff\">\\n<\/span><span style=\"color:#e6db74\">\u00af<\/span><span style=\"color:#ae81ff\">\\\\<\/span><span style=\"color:#e6db74\">_(\u30c4)_\/\u00af&#34;<\/span> }\n                    Button(<span style=\"color:#e6db74\">&#34;Flip&#34;<\/span>) { text <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#e6db74\">&#34;<\/span><span style=\"color:#ae81ff\">\\n<\/span><span style=\"color:#e6db74\">(\u256f\u00b0\u25a1\u00b0\uff09\u256f\ufe35 \u253b\u2501\u253b&#34;<\/span> }\n                    Spacer()\n                    Button(<span style=\"color:#e6db74\">&#34;Hide&#34;<\/span>) { focus = <span style=\"color:#66d9ef\">false<\/span> }\n                }\n            }\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/keyboard-toolbar-xcode-project.png\" width=\"600\" height=\"389\" alt=\"Keyboard Toolbar Xcode Project\">\n"},{"title":"How to expand and collapse cells in SwiftUI","link":"https:\/\/kamil.id\/2021\/08\/08\/how-to-expand-and-collapse\/","pubDate":"Sun, 08 Aug 2021 14:02:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/08\/08\/how-to-expand-and-collapse\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-expand-and-collapse-cells-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to expand and collapse cells in SwiftUI\">\n<p>Animations are a crucial but often neglected part of good UI. Correctly used can guide used in the app. In this article, you will learn how to make a list cell that expands on tap and apply animation to it.<\/p>\n<p>We will create a simple Todo List with subtasks.<\/p>\n<div style=\"padding:216.41% 0 0 0;position:relative;\"><iframe src=\"https:\/\/player.vimeo.com\/video\/584498693?h=895b305edf&badge=0&autopause=0&player_id=0&app_id=58479\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen style=\"position:absolute;top:0;left:0;width:100%;height:100%;\" title=\"How to expand and collapse cells in SwiftUI\"><\/iframe><\/div><script src=\"https:\/\/player.vimeo.com\/api\/player.js\"><\/script>\n<h2 id=\"models\">Models<\/h2>\n<p>First of all, let&rsquo;s make a models for this data.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Task<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: String = UUID().uuidString\n    <span style=\"color:#66d9ef\">let<\/span> title: String\n    <span style=\"color:#66d9ef\">let<\/span> subtask: [Subtask]\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Subtask<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: String = UUID().uuidString\n    <span style=\"color:#66d9ef\">let<\/span> title: String\n}\n<\/code><\/pre><\/div><p>Of course, it won&rsquo;t be a fully working example. In the final application, you will probably need additional fields for selected state, deadline, etc.<\/p>\n<h2 id=\"cells\">Cells<\/h2>\n<p>Then let&rsquo;s focus on cells. I decided to go with three separate cells designs. One for <code>Subtask<\/code> model:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">SubtaskCell<\/span>: View {\n    <span style=\"color:#66d9ef\">let<\/span> task: Subtask\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        HStack {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;circle&#34;<\/span>)\n                .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n            Text(task.title)\n        }\n    }\n}\n<\/code><\/pre><\/div><p>one when a new\/empty subtask:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">EmptySubtaskCell<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text: String = <span style=\"color:#e6db74\">&#34;&#34;<\/span>\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        HStack {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;circle&#34;<\/span>)\n                .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n            TextField(<span style=\"color:#e6db74\">&#34;new task&#34;<\/span>, text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n        }\n    }\n}\n<\/code><\/pre><\/div><p>and one for a <code>Task<\/code> model:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TaskCell<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> isExpanded: Bool = <span style=\"color:#66d9ef\">false<\/span>\n    \n    <span style=\"color:#66d9ef\">let<\/span> task: Task\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        content\n            .padding(.leading)\n            .frame(maxWidth: .infinity)\n    }\n    \n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> content: some View {\n        VStack(alignment: .leading, spacing: <span style=\"color:#ae81ff\">8<\/span>) {\n            header\n            <span style=\"color:#66d9ef\">if<\/span> isExpanded {\n                Group {\n                    ForEach(task.subtask) { subtask <span style=\"color:#66d9ef\">in<\/span>\n                        SubtaskCell(task: subtask)\n                    }\n                    EmptySubtaskCell()\n                }\n                .padding(.leading)\n            }\n            Divider()\n        }\n    }\n    \n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> header: some View {\n        HStack {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;square&#34;<\/span>)\n                .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n            Text(task.title)\n        }\n        .padding(.vertical, <span style=\"color:#ae81ff\">4<\/span>)\n        .onTapGesture {\n            withAnimation { isExpanded.toggle() }\n        }\n    }\n}\n<\/code><\/pre><\/div><p>That last one will support expanding and collapsing, so it&rsquo;s a bit bigger. Let&rsquo;s make a small dissection.<\/p>\n<p>In the body, we load content and ensure that the cell takes the entire width of a given view.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">var<\/span> body: some View {\n    content\n        .padding(.leading)\n        .frame(maxWidth: .infinity)\n}\n<\/code><\/pre><\/div><p>The <code>TaskCell<\/code> will store information about its state. You can find the <code>isExpanded<\/code> <code>@State<\/code> property wrapper on the top of it.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> isExpanded: Bool = <span style=\"color:#66d9ef\">false<\/span>\n<\/code><\/pre><\/div><p>The cell&rsquo;s content displays a header where the title and checkbox are displayed and subtasks if the cell is expanded. At the bottom, it also shows the <code>Divider<\/code> to separate one task from another.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> content: some View {\n    VStack(alignment: .leading, spacing: <span style=\"color:#ae81ff\">8<\/span>) {\n        header\n        <span style=\"color:#66d9ef\">if<\/span> isExpanded {\n            Group {\n                ForEach(task.subtask) { subtask <span style=\"color:#66d9ef\">in<\/span>\n                    SubtaskCell(task: subtask)\n                }\n                EmptySubtaskCell()\n            }\n            .padding(.leading)\n        }\n        Divider()\n    }\n}\n<\/code><\/pre><\/div><p>The cell&rsquo;s header is similar to the <code>SubtaskCell<\/code>, but it displays a square image instead of a circle. It also has the <code>onTapGesture<\/code> method, which toggles the <code>isExpanded<\/code> state.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"> <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> header: some View {\n    HStack {\n        Image(systemName: <span style=\"color:#e6db74\">&#34;square&#34;<\/span>)\n            .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n        Text(task.title)\n    }\n    .padding(.vertical, <span style=\"color:#ae81ff\">4<\/span>)\n    .onTapGesture { isExpanded.toggle() }\n}\n<\/code><\/pre><\/div><h2 id=\"todo-list\">ToDo List<\/h2>\n<p>With all these cells, you are ready to create a final view.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TasksView<\/span>: View {\n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">let<\/span> tasks: [Task] = [\n        Task(title: <span style=\"color:#e6db74\">&#34;Create playground&#34;<\/span>, subtask: []),\n        Task(title: <span style=\"color:#e6db74\">&#34;Write article&#34;<\/span>, subtask: []),\n        Task(\n            title: <span style=\"color:#e6db74\">&#34;Prepare assets&#34;<\/span>,\n            subtask: [\n                Subtask(title: <span style=\"color:#e6db74\">&#34;Cover image&#34;<\/span>),\n                Subtask(title: <span style=\"color:#e6db74\">&#34;Screenshots&#34;<\/span>)\n            ]\n        ),\n        Task(title: <span style=\"color:#e6db74\">&#34;Publish article&#34;<\/span>, subtask: [])\n    ]\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        NavigationView {\n            ScrollView {\n                ForEach(tasks) { task <span style=\"color:#66d9ef\">in<\/span>\n                    TaskCell(task: task)\n                        .animation(.<span style=\"color:#66d9ef\">default<\/span>)\n                }\n                .navigationTitle(<span style=\"color:#e6db74\">&#34;Todo List&#34;<\/span>)\n            }\n        }\n    }\n}\n<\/code><\/pre><\/div><p>At the top are some static <code>Tasks<\/code> hardcoded (for the production-ready application, you should store them in application state.)<\/p>\n<p>Body list all tasks using the <code>ForEach<\/code> view. And how I achieved this animation effect, you may ask. It was as simple as adding the <code>.animation(.default)<\/code> view modifier to the <code>TaskCell<\/code> view.<\/p>\n<h2 id=\"summary\">Summary<\/h2>\n<p>By following this tutorial, you will achieve an effect presented at the top of the article. With the help of SwiftUI, adding animations that delights the user experience can be straightforward.<\/p>\n<p>You can find the full code of this project below:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Task<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: String = UUID().uuidString\n    <span style=\"color:#66d9ef\">let<\/span> title: String\n    <span style=\"color:#66d9ef\">let<\/span> subtask: [Subtask]\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Subtask<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: String = UUID().uuidString\n    <span style=\"color:#66d9ef\">let<\/span> title: String\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TasksView<\/span>: View {\n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">let<\/span> tasks: [Task] = [\n        Task(title: <span style=\"color:#e6db74\">&#34;Create playground&#34;<\/span>, subtask: []),\n        Task(title: <span style=\"color:#e6db74\">&#34;Write article&#34;<\/span>, subtask: []),\n        Task(\n            title: <span style=\"color:#e6db74\">&#34;Prepare assets&#34;<\/span>,\n            subtask: [\n                Subtask(title: <span style=\"color:#e6db74\">&#34;Cover image&#34;<\/span>),\n                Subtask(title: <span style=\"color:#e6db74\">&#34;Screenshots&#34;<\/span>)\n            ]\n        ),\n        Task(title: <span style=\"color:#e6db74\">&#34;Publish article&#34;<\/span>, subtask: [])\n    ]\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        NavigationView {\n            ScrollView {\n                ForEach(tasks) { task <span style=\"color:#66d9ef\">in<\/span>\n                    TaskCell(task: task)\n                        .animation(.<span style=\"color:#66d9ef\">default<\/span>)\n                }\n                .navigationTitle(<span style=\"color:#e6db74\">&#34;Todo List&#34;<\/span>)\n            }\n        }\n    }\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TaskCell<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> isExpanded: Bool = <span style=\"color:#66d9ef\">false<\/span>\n    \n    <span style=\"color:#66d9ef\">let<\/span> task: Task\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        content\n            .padding(.leading)\n            .frame(maxWidth: .infinity)\n    }\n    \n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> content: some View {\n        VStack(alignment: .leading, spacing: <span style=\"color:#ae81ff\">8<\/span>) {\n            header\n            <span style=\"color:#66d9ef\">if<\/span> isExpanded {\n                Group {\n                    ForEach(task.subtask) { subtask <span style=\"color:#66d9ef\">in<\/span>\n                        SubtaskCell(task: subtask)\n                    }\n                    EmptySubtaskCell()\n                }\n                .padding(.leading)\n            }\n            Divider()\n        }\n    }\n    \n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> header: some View {\n        HStack {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;square&#34;<\/span>)\n                .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n            Text(task.title)\n        }\n        .padding(.vertical, <span style=\"color:#ae81ff\">4<\/span>)\n        .onTapGesture { isExpanded.toggle() }\n    }\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">SubtaskCell<\/span>: View {\n    <span style=\"color:#66d9ef\">let<\/span> task: Subtask\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        HStack {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;circle&#34;<\/span>)\n                .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n            Text(task.title)\n        }\n    }\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">EmptySubtaskCell<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text: String = <span style=\"color:#e6db74\">&#34;&#34;<\/span>\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        HStack {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;circle&#34;<\/span>)\n                .foregroundColor(Color.primary.opacity(<span style=\"color:#ae81ff\">0.2<\/span>))\n            TextField(<span style=\"color:#e6db74\">&#34;new task&#34;<\/span>, text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n        }\n    }\n}\n<\/code><\/pre><\/div>"},{"title":"How to setup Code Climate Quality test coverage with Bitrise","link":"https:\/\/kamil.id\/2021\/07\/24\/how-to-setup-code-climate\/","pubDate":"Sat, 24 Jul 2021 17:07:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/07\/24\/how-to-setup-code-climate\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-setup-code-climate-quality-code-coverage-with-bitrise.png\" width=\"600\" height=\"360\" alt=\"How to setup Code Climate Quality test coverage with Bitrise\">\n<p><a href=\"https:\/\/codeclimate.com\/quality\/\">Quality by Code Climate<\/a> is a web service that gives you analytics for your code. It analyzes your code for code smells, and with proper CI\/CD integration, it can track changes in test coverage data.<\/p>\n<p>This article will list, step by step, how to set up Code Climate test coverage upload from <a href=\"https:\/\/www.bitrise.io\/\">Bitrise<\/a> - probably most famous and widely used mobile Continues Integration and Continues Delivery service.<\/p>\n<p><strong>Initial assumption<\/strong>: Your GitHub repository is added to the Quality by Code Climate and the Bitrise.<\/p>\n<ul>\n<li>\n<p>Get Code Climate&rsquo;s test reporters ID - visit <code>Repo Settings<\/code> on Code Climate and open <code>Test coverage<\/code>.<\/p>\n<\/li>\n<li>\n<p>Add ID from the previous step as a Bitrise Secret with a name <code>CC_TEST_REPORTER_ID<\/code> (if you want to test Pull Requests active <code>Expose for Pull Requests?<\/code>)<\/p>\n<\/li>\n<li>\n<p>Generate <a href=\"https:\/\/github.com\/settings\/tokens\">GitHub personal access token<\/a> (only <code>public_repo<\/code> permission is needed)<\/p>\n<\/li>\n<li>\n<p>Add token from the previous step as a Bitrise Secret with a name <code>GITHUB_ACCESS_TOKEN<\/code> (if you want to test Pull Requests active <code>Expose for Pull Requests?<\/code>)\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/bitrise-secrets.png\" width=\"600\" height=\"152\" alt=\"Bitrise secrets\"><\/p>\n<\/li>\n<li>\n<p>Turn on gathering test coverage in your Xcode project. <code>Edit Scheme...<\/code> -&gt; <code>Test<\/code> phase and select checkbox on <code>Gather coverage for...<\/code> in <code>Code Coverage<\/code> section.\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/xcode-test-coverage.png\" width=\"600\" height=\"328\" alt=\"Xcode - gather coverage\"><\/p>\n<\/li>\n<li>\n<p>In Bitrise, go to your Tests workflow, and before <code>Xcode Test for iOS<\/code> step, add a new Script phase with content visible below. It will download Code Climate test runner (<code>cc-test-reporter<\/code>) and updates Code Climate that test coverage is being prepared.<\/p>\n<\/li>\n<\/ul>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-bash\" data-lang=\"bash\"><span style=\"color:#75715e\">#!\/usr\/bin\/env bash\n<\/span><span style=\"color:#75715e\"><\/span>\ncurl -L https:\/\/codeclimate.com\/downloads\/test-reporter\/test-reporter-latest-darwin-amd64 &gt; .\/cc-test-reporter\nchmod +x .\/cc-test-reporter\n.\/cc-test-reporter before-build\n<\/code><\/pre><\/div><ul>\n<li>Add a new step after <code>Xcode Test for iOS<\/code> and paste provided content. This script uses <code>xcrun xccov<\/code> to format <code>Tests.xcresult<\/code> file to JSON and uploads it using the previously downloaded <code>cc-test-reporter<\/code> script.<\/li>\n<\/ul>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-bash\" data-lang=\"bash\"><span style=\"color:#75715e\">#!\/usr\/bin\/env bash\n<\/span><span style=\"color:#75715e\"><\/span>\nxcrun xccov view --report $BITRISE_XCRESULT_PATH --json &gt; coverage.json\n.\/cc-test-reporter after-build --coverage-input-type xccov\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/bitrise-steps.png\" width=\"600\" height=\"522\" alt=\"Bitrise steps needed for test coverage setup\">\n<ul>\n<li>In Xcode Test for iOS step set <code>Generate code coverage files<\/code>? to <code>no<\/code>. Note: I&rsquo;m not sure why, but I had a problem finishing that step with this set to <code>yes<\/code>.<\/li>\n<\/ul>\n<p>That&rsquo;s it. With that few simple steps, you can send test coverage data from Bitrise to Code Climate.<\/p>\n"},{"title":"How to dim Image for dark mode using ColorScheme","link":"https:\/\/kamil.id\/2021\/07\/11\/how-to-dim-image-for\/","pubDate":"Sun, 11 Jul 2021 18:04:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/07\/11\/how-to-dim-image-for\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-dim-image-for-dark-mode-using-colorscheme.png\" width=\"600\" height=\"360\" alt=\"How to dim Image for dark mode using ColorScheme\">\n<p>If you are using defaults colors for text and backgrounds, iOS\/macOS handles dark mode literary by itself. But sometimes, you want to go with your style to make a brand more appealing or differentiate from the competition. Adjusting to dark mode required more work then, but still, the framework offers you many different options to make your life easier.<\/p>\n<p>This article will explain how to use the <code>ColorScheme<\/code> environment variable to differentiate between light and dark mode and show overlay over the image when it is visible in the dark mode.<\/p>\n<p>Let&rsquo;s say that you are working on the sign-in screen for your application. You decided to use an image as a background to make it more appealing for users. But then you realize that you pick a photo with too vibrant colors for dark mode. There are few solutions for that.<\/p>\n<p>Xcode project assets can support different assets for different modes. So you can edit the current image or find a different one that the application will use for a dark mode. But let&rsquo;s say that you want to add new (usually big) assets to the project. What is the other option? You can use the <code>ColorScheme<\/code> environment variable to check the current mode and display a dark overlay above the image.<\/p>\n<p>SwiftUI offers an Environment property wrapper to get environment variables. One of them, available by default under the <code>colorScheme<\/code> key, is a <code>ColorScheme<\/code> enum which can store two values, <code>light<\/code> and <code>dark<\/code>. To get that setting, add:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@Environment(<span style=\"color:#960050;background-color:#1e0010\">\\<\/span>.colorScheme) <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> colorScheme: ColorScheme\n<\/code><\/pre><\/div><p>to your view.<\/p>\n<p>Like nearly everything in SwiftUI, you can achieve a dim effect in many ways. I decided to go with <code>ZStack<\/code> and to display a rectangle with a translucent color.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">if<\/span> colorScheme == .dark {\n    Rectangle()\n        .fill(Color.black.opacity(<span style=\"color:#ae81ff\">0.3<\/span>))\n}\n<\/code><\/pre><\/div><p>You can check the complete code example:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">BackgroundView<\/span>: View {\n    @Environment(<span style=\"color:#960050;background-color:#1e0010\">\\<\/span>.colorScheme) <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> colorScheme: ColorScheme\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        ZStack {\n            Image(<span style=\"color:#e6db74\">&#34;background&#34;<\/span>)\n                .resizable()\n                .scaledToFill()\n                .frame(minWidth: <span style=\"color:#ae81ff\">0<\/span>, maxWidth: .infinity)\n            <span style=\"color:#66d9ef\">if<\/span> colorScheme == .dark {\n                Rectangle()\n                    .fill(Color.black.opacity(<span style=\"color:#ae81ff\">0.3<\/span>))\n            }\n            Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n                .font(.largeTitle)\n                .bold()\n        }\n        .ignoresSafeArea()\n    }\n}\n<\/code><\/pre><\/div><p>The gallery below presents this effect in light and dark mode. As you can notice, the Swift Wombat title color was adjusted automatically.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/xcode-project-color-scheme-dark.png\" width=\"600\" height=\"432\" alt=\"Xcode Image dim in dark mode. Example project.\">\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/xcode-project-color-scheme-light.png\" width=\"600\" height=\"432\" alt=\"Xcode Image dim in light mode. Example project.\">\n"},{"title":"How to add Pull to Refresh to the SwiftUI view","link":"https:\/\/kamil.id\/2021\/06\/27\/how-to-add-pull-to\/","pubDate":"Sun, 27 Jun 2021 13:59:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/06\/27\/how-to-add-pull-to\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-add-pull-to-refresh-to-the-swiftui-view.png\" width=\"600\" height=\"360\" alt=\"How to add Pull to Refresh to the SwiftUI view\">\n<p>Pull to Refresh is a widespread UX pattern on mobile. Drag a list down and load new items. You can find that in all social media applications and almost all other apps that display data download from servers.<\/p>\n<p>To achieve this in previous versions of SwiftUI, you will have to use <code>UIKit<\/code> code, create your view, or third-party library. But SWiftUI 3 brings a native <code>ViewModifier<\/code> that changes adding Pull to Refresh into child&rsquo;s play. Let&rsquo;s dive into code.<\/p>\n<p>To display Pull to Refresh, you have to add a <code>refreshable<\/code> modifier to the scrollable view, most commonly <code>List<\/code> or <code>Grid<\/code>. The <code>refreshable<\/code> view modifier uses async\/await syntax and handles dismissing the refresh indicator automatically.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> rows = <span style=\"color:#ae81ff\">0<\/span>\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        List(<span style=\"color:#ae81ff\">0.<\/span>.&lt;rows, id: <span style=\"color:#960050;background-color:#1e0010\">\\<\/span>.<span style=\"color:#66d9ef\">self<\/span>) { number <span style=\"color:#66d9ef\">in<\/span>\n            Text(<span style=\"color:#e6db74\">&#34;row <\/span><span style=\"color:#e6db74\">\\(<\/span>number<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\n        }\n        .refreshable {\n            await Task.sleep(<span style=\"color:#ae81ff\">5_000_000_000<\/span>) <span style=\"color:#75715e\">\/\/ wait 5s<\/span>\n            rows <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#ae81ff\">10<\/span>\n        }\n    }\n}\n<\/code><\/pre><\/div><p>For this example, I&rsquo;m using a <code>Task.sleep<\/code> that simply waits for a given number of nanoseconds to pass. Typically, you will perform time-consuming asynchronous (like downloading data from the network) operations here.<\/p>\n<p>And that&rsquo;s it. This code sample will add full Pull to Refresh handling. But there is one more thing that is worth mentioning. SwiftUI 3 added a new modifier to download initial data for a given view. This modifier is called <code>task<\/code> and also expects the async\/await syntax.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> rows = <span style=\"color:#ae81ff\">0<\/span>\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        List(<span style=\"color:#ae81ff\">0.<\/span>.&lt;rows, id: <span style=\"color:#960050;background-color:#1e0010\">\\<\/span>.<span style=\"color:#66d9ef\">self<\/span>) { number <span style=\"color:#66d9ef\">in<\/span>\n            Text(<span style=\"color:#e6db74\">&#34;row <\/span><span style=\"color:#e6db74\">\\(<\/span>number<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\n        }\n        .task {\n            await Task.sleep(<span style=\"color:#ae81ff\">3_000_000_000<\/span>) <span style=\"color:#75715e\">\/\/ wait 3s<\/span>\n            rows = <span style=\"color:#ae81ff\">10<\/span>\n        }\n        .refreshable {\n            await Task.sleep(<span style=\"color:#ae81ff\">5_000_000_000<\/span>) <span style=\"color:#75715e\">\/\/ wait 5s<\/span>\n            rows <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#ae81ff\">10<\/span>\n        }\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/xcode-refreshable-experiment.png\" width=\"600\" height=\"375\" alt=\"Xcode refreshable experiment\">\n"},{"title":"How to display images from the web using AsyncImage","link":"https:\/\/kamil.id\/2021\/06\/12\/how-to-display-images-from\/","pubDate":"Sat, 12 Jun 2021 15:54:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/06\/12\/how-to-display-images-from\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-display-images-from-the-web-using-asyncimage.png\" width=\"600\" height=\"360\" alt=\"How to display images from the web using AsyncImage\">\n<p>Each WWDC brings lots of new goods for all Apple ecosystem developers. The 2021 edition wasn&rsquo;t different. AsyncImage view is a new SwiftUI addition that expects a URL instead of an asset to display images. Read further to learn how to use it.<\/p>\n<p>Displaying images from the web is a widespread task in mobile applications. You can see this in all social media applications, web-based knowledge bases, or apps that stream files from servers. It requires more work than displaying images locally. After all, we have to wait until the image is loaded (usually displaying a placeholder) and handle situations where the network connection is not reliable (or the file doesn&rsquo;t exist anymore). <code>AsyncView<\/code> is created to make those operations easier. When it comes to displaying images, it uses an <code>Image<\/code> view underneath.<\/p>\n<p>The simplest form of AsyncView requires only the <code>url<\/code> parameter with the URL object. This <code>url<\/code> parameter is optional, so you don&rsquo;t have to check its existence when creating it using the <code>URL(string:_)<\/code> constructor.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">let<\/span> url = URL(string: <span style=\"color:#e6db74\">&#34;http:\/\/placekitten.com\/200\/200&#34;<\/span>)\nAsyncImage(url: url)\n<\/code><\/pre><\/div><p>But often, you may want to do more with a result. One of the most common scenarios was to resize the image to fit its frame.  The <code>AsyncImage<\/code> <a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/asyncimage\/init(url:scale:content:placeholder:)\">first initializer<\/a> can handle <code>scale<\/code> parameter and two convenient closures - <code>content<\/code> and <code>placeholder<\/code>. The first one performs operations on the <code>Image<\/code> view when it is finally loaded, and the second one returns a view displayed when an image is loading.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">AsyncImage(url: url) { image <span style=\"color:#66d9ef\">in<\/span>\n    image.resizable()\n} placeholder: {\n    Text(<span style=\"color:#e6db74\">&#34;Loading...&#34;<\/span>)\n}\n<\/code><\/pre><\/div><p>With content closure, you can resize the image, fit it to content or apply rounded corners.<\/p>\n<p>But there is a <a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/asyncimage\/init(url:scale:transaction:content:)\">second initializer<\/a> that allows for more advanced control. You will probably be using that version more often. It also supports <code>url<\/code> and <code>scale<\/code> properties, but there is a new <code>transaction<\/code> parameter and content closure gets <a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/asyncimagephase\">AsyncImagePhase enum<\/a>. You can use the data provided in that enum to return a view for different phases of image loading. When the network file is loaded (<code>success<\/code> phase), you will get an <code>Image<\/code> view. For <code>failure<\/code> error is returned. There is a third empty phase, which means that the file is being loaded. The <code>transaction<\/code> parameter is used to provide an animation that is applied when phases change.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">AsyncImage(\n    url: url,\n    transaction: Transaction(\n        animation: .easeInOut\n    )\n) { phase <span style=\"color:#66d9ef\">in<\/span>\n     <span style=\"color:#66d9ef\">if<\/span> <span style=\"color:#66d9ef\">let<\/span> image = phase.image {\n         image.resizable()\n    } <span style=\"color:#66d9ef\">else<\/span> <span style=\"color:#66d9ef\">if<\/span> phase.error <span style=\"color:#f92672\">!=<\/span> <span style=\"color:#66d9ef\">nil<\/span> {\n        Text(<span style=\"color:#e6db74\">&#34;Error!&#34;<\/span>)\n    } <span style=\"color:#66d9ef\">else<\/span> {\n        Text(<span style=\"color:#e6db74\">&#34;Loading...&#34;<\/span>)\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/asyncimage-swiftui-playground.png\" width=\"600\" height=\"353\" alt=\"AsyncImage SwiftUI Playground\">\n"},{"title":"How to change the Button view style","link":"https:\/\/kamil.id\/2021\/05\/30\/how-to-change-the-button\/","pubDate":"Sun, 30 May 2021 19:06:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/05\/30\/how-to-change-the-button\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-change-the-button-view-style.png\" width=\"600\" height=\"360\" alt=\"How to change the Button view style\">\n<p><code>Button<\/code>, as one of the most common UI elements, is used for versatile sets of actions. But actions can have a different level of importance. Sometimes you want to highlight the primary activity or mark the destructive one in red. You can do this by wrapping the Button view in a custom view, but SwiftUI creators design a better way by using <code>buttonStyle(_:)<\/code> view modifier.<\/p>\n<p>The <code>buttonStyle<\/code> modifier accepts one argument, which is an object that implements the <code>PrimitiveButtonStyle<\/code> protocol. There are some predefined structs that you can use out of the box - <code>DefaultButtonStyle<\/code>, <code>PlainButtonStyle<\/code>, and <code>BorderlessButtonStyle<\/code>. To use them, call:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Button(<span style=\"color:#e6db74\">&#34;Default button style&#34;<\/span>, action: {})\n    .buttonStyle(DefaultButtonStyle())\n    \nButton(<span style=\"color:#e6db74\">&#34;Plain button style&#34;<\/span>, action: {})\n    .buttonStyle(PlainButtonStyle())\n    \nButton(<span style=\"color:#e6db74\">&#34;Borderless button style&#34;<\/span>, action: {})\n    .buttonStyle(BorderlessButtonStyle())\n<\/code><\/pre><\/div><p>You can look at the bottom of the article to find out how they look on iOS. But that styles adjust to the platform. They will look different on iOS, watchOS, and macOS.<\/p>\n<p>Those are still minimal options. But you don&rsquo;t have to stop here. Create your struct, implement <code>PrimitiveButtonStyle<\/code> protocol, which requires only one <code>makeBody(configuration: Configuration) -&gt; some View<\/code> method, and you can create as many styles as you want.<\/p>\n<p>The makeBody function is responsible for creating a button, so usually it w contains something like this <code>Button(configuration)<\/code>, but you can modify the configuration or create a new one before you pass it to the Button view initializer.<\/p>\n<p>In the example below, I created a button with a rounded border. Background color can be controller by the <code>color<\/code> property:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">BorderedButtonStyle<\/span>: PrimitiveButtonStyle {\n    <span style=\"color:#66d9ef\">let<\/span> color: Color\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeBody<\/span>(configuration: Configuration) -&gt; some View {\n        ZStack {\n            RoundedRectangle(cornerRadius: <span style=\"color:#ae81ff\">16<\/span>)\n                .foregroundColor(color)\n            Button(configuration)\n                .foregroundColor(.white)\n                .padding()\n        }\n    }\n}\n<\/code><\/pre><\/div><p>To apply the new style to the Button, use the same modifier as above:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Button(<span style=\"color:#e6db74\">&#34;Bordered button style&#34;<\/span>, action: {})\n    .buttonStyle(BorderedButtonStyle(color: .orange))\n<\/code><\/pre><\/div><p>Custom button styles can be a straightforward solution to prepare a tailored set of button styles dedicated to your app.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/buttonstyle-xcode-playground.png\" width=\"600\" height=\"383\" alt=\"Xcode playground to test different button styles\">\n"},{"title":"How to use PersonNameComponentsFormatter","link":"https:\/\/kamil.id\/2021\/05\/23\/how-to-use-personnamecomponentsformatter\/","pubDate":"Sun, 23 May 2021 14:44:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/05\/23\/how-to-use-personnamecomponentsformatter\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-use-personname-componentsformatter.png\" width=\"600\" height=\"360\" alt=\"How to use PersonNameComponentsFormatter\">\n<p>Foundation framework available for iOS, macOS, iPadOS, and other Apple platforms hides many gems that you can use to simplify operations required in nearly every application. One of the very often used sets of features are formatters. You probably are familiar with <code>DateFormatters<\/code>, but in today&rsquo;s article, I&rsquo;ll describe how to use <code>PersonNameComponentsFormatter<\/code>, which you can use to parse and format a person&rsquo;s name.<\/p>\n<p>The structure of personal names varies between different locales. On the other hand, there are significant and meaningful for persons that use them. That&rsquo;s a reason you should treat them with respect and very carefully. <code>PersonNameComponentsFormatter<\/code> can help you with that. This formatter can parse string data provided and separated them into <code>PersonNameComponents<\/code>, and get that structure to display name using the correct locale.<\/p>\n<p>First, you have to create an instance of the <code>PersonNameComponentsFormatter<\/code>:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">let<\/span> formatter = PersonNameComponentsFormatter()\n<\/code><\/pre><\/div><p>To separate name string for components use <code>personNameComponents(from:)<\/code> function:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">if<\/span> <span style=\"color:#66d9ef\">let<\/span> components = formatter.personNameComponents(\n    from: <span style=\"color:#e6db74\">&#34;Sir David Frederick Attenborough&#34;<\/span>\n) {\n    print(components)\n    <span style=\"color:#75715e\">\/* Prints:\n<\/span><span style=\"color:#75715e\">       namePrefix: Sir\n<\/span><span style=\"color:#75715e\">       givenName: David\n<\/span><span style=\"color:#75715e\">       middleName: Frederick\n<\/span><span style=\"color:#75715e\">       familyName: Attenborough\n<\/span><span style=\"color:#75715e\">    *\/<\/span>\n}\n<\/code><\/pre><\/div><p>If you already have components (for example, created from the form data), you can use them with the same class to build different data representations. You can use one of 4 styles <code>short<\/code>, <code>medium(default)<\/code>, <code>long<\/code>, <code>abbreviated<\/code>.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">formatter.style = .<span style=\"color:#66d9ef\">default<\/span>\nprint(formatter.string(from: components))\n<span style=\"color:#75715e\">\/\/ David Attenborough<\/span>\n\nformatter.style = .abbreviated\nprint(formatter.string(from: components))\n<span style=\"color:#75715e\">\/\/ DA<\/span>\n\nformatter.style = .long\nprint(formatter.string(from: components))\n<span style=\"color:#75715e\">\/\/ Sir David Frederick Attenborough<\/span>\n\nformatter.style = .medium\nprint(formatter.string(from: components))\n<span style=\"color:#75715e\">\/\/ David Attenborough<\/span>\n\nformatter.style = .short\nprint(formatter.string(from: components))\n<span style=\"color:#75715e\">\/\/ David<\/span>\n<\/code><\/pre><\/div><p>Additionally, <code>PersonNameComponentsFormatter<\/code> can prepare an Attributed String.<\/p>\n<p>As you can see, <code>PersonNameComponentsFormatter<\/code> is very easy to use. With correctly collected or parsed data, you will create correct abbreviations or long-style formatted person details.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/personnamecomponentsformatter-xcode-playground.png\" width=\"600\" height=\"460\" alt=\"PersonNameComponentsFormatter Xcode Playground\">\n"},{"title":"How to control Image view interpolation in SwiftUI","link":"https:\/\/kamil.id\/2021\/05\/09\/how-to-control-image-view\/","pubDate":"Sun, 09 May 2021 14:16:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/05\/09\/how-to-control-image-view\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-control-image-view-interpolation-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to control Image view interpolation in SwiftUI\">\n<p>When you are scaling up (and down) a small image in SwiftUI, there is an operation called interpolation. The size of a current image pixel is calculated based on neighbor pixels. It gave a more natural and better-looking effect, but it also means that the image appears blurry (look at the first image in the example above). More advanced interpolations also increase computational complexity.<\/p>\n<p>Sometimes, you want to display the image in a more pixelated form (second image in the example above). There is a view modifier for that. Its name is an <code>interpolation(...)<\/code> (surprise, surprise).<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/image-interpolation-difference.png\" width=\"323\" height=\"600\" alt=\"Top: Interpolation - default, Bottom: Interpolation - none\">\n<p>Top: Interpolation - default, Bottom: Interpolation - none<\/p>\n<p>Using this modifier is very easy. It expects one of four <code>Interpolation<\/code> enum values: <code>high<\/code>, <code>medium<\/code>, <code>low<\/code>, and <code>none<\/code>. The first three will control interpolation quality, and the last one goes with the most straightforward approach of duplicating current pixel values (and gives pixelated effect).<\/p>\n<p>To change interpolation quality, call the given view modifier on Image view:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Image(<span style=\"color:#e6db74\">&#34;wombat&#34;<\/span>)\n    .interpolation(.<span style=\"color:#66d9ef\">none<\/span>)\n<\/code><\/pre><\/div><p>You will probably not need that function too often, but it&rsquo;s good to know its existence and play with that setting a bit.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/image-interpolation-xcode-playground.png\" width=\"600\" height=\"355\" alt=\"Image interpolation Xcode playground\">\n"},{"title":"How to display alerts in SwiftUI","link":"https:\/\/kamil.id\/2021\/05\/03\/how-to-display-alerts-in\/","pubDate":"Mon, 03 May 2021 12:19:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/05\/03\/how-to-display-alerts-in\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-display-alerts-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to display alerts in SwiftUI\">\n<p>If you are an iOS or macOS user, you have seen alerts many times. Alerts are components that inform you about some errors or ask about some destructive actions. It would be best if you were careful not to overuse them in your app because it may distract users.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/swiftui-alert-default-and-destructive2x.png\" width=\"564\" height=\"278\" alt=\"iOS Alert Example\">\n<p>SwiftUI offers a structure that makes displaying alerts very easy, but you must remember two limitations:<\/p>\n<ol>\n<li>\n<p>Due to the nature of SwiftUI, you must specify your alerts as an element of the view&rsquo;s tree. You will expect that displaying an alert should be a function, but it will be imperative programming. In the declarative paradigm, you specify the whole interface before the app starts. Messages displayed to users must also conform to that rule.<\/p>\n<\/li>\n<li>\n<p>You will add alerts as view modifiers. If you add two of them at the same level, the second one will override the first. In that case, it&rsquo;s better to create an enum that will combine all alerts that you want to present or, as you will see in the example below, add alerts somewhere lower the view&rsquo;s tree.<\/p>\n<\/li>\n<\/ol>\n<p>With that two limitations in mind, you can go to the fun part - implementation. Alerts are added to the view&rsquo;s tree at the beginning, so they need some <code>Binding<\/code>, usually a <code>@State<\/code> that will tell they should be displayed or not.<\/p>\n<h2 id=\"simple-alert-view-modifier\">Simple Alert View Modifier<\/h2>\n<p>There are two versions of the <code>alert(...)<\/code> view modifier. The first one expects a boolean value that represents <code>isPresented<\/code> state of alert. You modify your state, setting it true to display it.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">SimpleAlert<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> showAlert = <span style=\"color:#66d9ef\">false<\/span>\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        Button(<span style=\"color:#e6db74\">&#34;Show alert&#34;<\/span>) {\n            showAlert = <span style=\"color:#66d9ef\">true<\/span>\n        }\n        .alert(isPresented: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>showAlert) {\n            <span style=\"color:#75715e\">\/\/ Alert view<\/span>\n        }\n    }\n}\n<\/code><\/pre><\/div><p>One thing is worth noticing. You need to use <code>$<\/code> before the name of your <code>@State<\/code> variable to get <code>Binding&lt;Bool&gt;<\/code> from it.<\/p>\n<p>The content block of the <code>alert(..)<\/code> modifier expects an <code>Alert<\/code> view. Its initializers look like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">public<\/span> <span style=\"color:#66d9ef\">init<\/span>(\n    title: Text,\n    message: Text? = <span style=\"color:#66d9ef\">nil<\/span>,\n    dismissButton: Alert.Button? = <span style=\"color:#66d9ef\">nil<\/span>\n)\n<span style=\"color:#66d9ef\">public<\/span> <span style=\"color:#66d9ef\">init<\/span>(\n    title: Text,\n    message: Text? = <span style=\"color:#66d9ef\">nil<\/span>,\n    primaryButton: Alert.Button,\n    secondaryButton: Alert.Button\n)\n<\/code><\/pre><\/div><p>You can use the first one for simple confirmation messages (like error or info messages). Only title Text view is required for this one. By default, it displays an OK button.<\/p>\n<p>The second one gives you more freedom. You must set a primaryButton and a secondaryButton for it. You can select from <code>cancel(...)<\/code>, <code>default(...)<\/code> and <code>destructive(...)<\/code> button styles. System calls primary button when the view is dismissed, so watch out to not set any destructive action there.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Alert(\n    title: Text(<span style=\"color:#e6db74\">&#34;Uninstall this application&#34;<\/span>),\n    message: Text(<span style=\"color:#e6db74\">&#34;Do you want to uninstall this application? This action cannot be undone.&#34;<\/span>),\n    primaryButton: .cancel(),\n    secondaryButton: .destructive(\n        Text(<span style=\"color:#e6db74\">&#34;Uninstall&#34;<\/span>),\n        action: { <span style=\"color:#75715e\">\/* do something *\/<\/span> }\n    )\n)\n<\/code><\/pre><\/div><p>You don&rsquo;t have to worry about setting <code>showAlert<\/code> to <code>false<\/code> again. SwiftUI will handle this for you. The cancel button is empty in this example.<\/p>\n<p>Full code to display simple alert look like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">SimpleAlert<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> showAlert = <span style=\"color:#66d9ef\">false<\/span>\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        Button(<span style=\"color:#e6db74\">&#34;Show alert&#34;<\/span>) {\n            showAlert = <span style=\"color:#66d9ef\">true<\/span>\n        }\n        .alert(isPresented: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>showAlert) {\n            Alert(\n                title: Text(<span style=\"color:#e6db74\">&#34;Uninstall this application&#34;<\/span>),\n                message: Text(<span style=\"color:#e6db74\">&#34;Do you want to uninstall this application? This action cannot be undone.&#34;<\/span>),\n                primaryButton: .cancel(),\n                secondaryButton: .destructive(\n                    Text(<span style=\"color:#e6db74\">&#34;Uninstall&#34;<\/span>),\n                    action: { <span style=\"color:#75715e\">\/* do something *\/<\/span> }\n                )\n            )\n        }\n    }\n}\n<\/code><\/pre><\/div><h2 id=\"advance-alert-view-modifier\">Advance Alert View Modifier<\/h2>\n<p>The second version of <code>alert(...)<\/code> can be used when the Alert state depends on the property bound to it. Instead of <code>isPresented<\/code>, you provide binding to an optional <code>item<\/code> - a struct, class, or enum that conforms to <code>Identifiable<\/code> protocol.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">enum<\/span> <span style=\"color:#a6e22e\">Animal<\/span>: String, CaseIterable, Identifiable {\n    <span style=\"color:#66d9ef\">case<\/span> wombat, koala, platypus\n\n    <span style=\"color:#66d9ef\">var<\/span> id: String { rawValue }\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">AnimalPicker<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> selectedAnimal: Animal?\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        VStack {\n            Text(<span style=\"color:#e6db74\">&#34;Please select an animal:&#34;<\/span>)\n            button(<span style=\"color:#66d9ef\">for<\/span>: .wombat)\n            button(<span style=\"color:#66d9ef\">for<\/span>: .koala)\n            button(<span style=\"color:#66d9ef\">for<\/span>: .platypus)\n        }\n        .alert(item: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>selectedAnimal) { animal <span style=\"color:#66d9ef\">in<\/span>\n            Alert(\n                title: Text(<span style=\"color:#e6db74\">&#34;Selected animal:&#34;<\/span>),\n                message: Text(animal.rawValue.capitalized)\n            )\n        }\n    }\n\n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">button<\/span>(<span style=\"color:#66d9ef\">for<\/span> animal: Animal) -&gt; some View {\n        Button(animal.rawValue.capitalized) {\n            selectedAnimal = animal\n        }\n    }\n}\n<\/code><\/pre><\/div><p>Content block of that version of the view modifier the same as the previous one expects Alert view, but it provides you a selected item. When the selected item is nil alert is not displayed. But when you set it to an existing object, the <code>Alert<\/code> view will show. When the message is dismissed, the selected item is set back to <code>nil<\/code>.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/xcode-alert-playground.png\" width=\"600\" height=\"386\" alt=\"Xcode Playground where you can experiment with Alert views\">\n"},{"title":"How to synchronize View and Model with SwiftUI's EnvironmentObject","link":"https:\/\/kamil.id\/2021\/04\/25\/how-to-synchronize-view-and\/","pubDate":"Sun, 25 Apr 2021 12:42:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/04\/25\/how-to-synchronize-view-and\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-synchronize-view-and-model-with-swiftui-s-environmentobject.png\" width=\"600\" height=\"360\" alt=\"How to synchronize View and Model with SwiftUI's EnvironmentObject\">\n<p>SwiftUI offers an easy way to inject your model classes into a view hierarchy. Additionally, it handles model changes pretty automatically, and only a tiny amount of additional code is needed from your side. In this article, I&rsquo;ll explain how to provide and retrieve <code>@EnvironmentObject<\/code> anywhere within your views hierarchy.<\/p>\n<p>Why do you need an environment object, you may ask? It simplifies your code. Of course, you can create a @State or @StateObject in your top view and provide it as Binding down below, but this will make your code less modular. Think of environment objects like a dependency injection mechanism. You provide your model in one place, and then in another, you can read it or perform actions. My favorite Redux-like state management library <a href=\"https:\/\/github.com\/StevenLambion\/SwiftDux\">SwiftDux<\/a> uses environment objects to provide store and action dispatcher to any view down the graph.<\/p>\n<p>The first puzzle you need is a class (model) that you will pass as an environment object. It needs to conform to the <code>ObservableObject<\/code> protocol. In that class, you can use the <code>@Published<\/code> property wrapper to expose a variable. When you change the value of the <code>@Published<\/code> variable, it will inform <code>ObservableObject<\/code>, and SwiftUI will handle the rest. Of course, a given object can contain standard variables and methods as well.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">class<\/span> <span style=\"color:#a6e22e\">Counter<\/span>: ObservableObject {\n    @Published <span style=\"color:#66d9ef\">var<\/span> value = <span style=\"color:#ae81ff\">0<\/span>\n}\n<\/code><\/pre><\/div><p>Now, when you have your model ready, you must find a place to create an instance of it and inject it into the SwiftUI view structure. Usually, this is the first view of the view&rsquo;s hierarchy. But it doesn&rsquo;t have to be. Sometimes, you want to provide some data to just a part of a structure. When you pick your place, create an instance of your model class using the <code>@StateObject<\/code> property wrapper, and then inject it using the <code>environmentObject<\/code> view modifier<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @StateObject <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> counter = Counter()\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        CounterView()\n            .environmentObject(counter)\n    }\n}\n<\/code><\/pre><\/div><p>You created your model, provided it for SwiftUI views, so it&rsquo;s time to learn how to use it. To retrieve your model, you should use the <code>@EnvironmentObject<\/code> property wrapper. You can operate on the provided object, and SwiftUI will refresh it in other places of the UI where the given environment object is used.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">CounterView<\/span>: View {\n    @EnvironmentObject <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> counter: Counter\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        VStack {\n            Text(<span style=\"color:#e6db74\">&#34;<\/span><span style=\"color:#e6db74\">\\(<\/span>counter.value<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\n            Divider()\n            IncrementView()\n        }\n    }\n}\n<\/code><\/pre><\/div><div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">IncrementView<\/span>: View {\n    @EnvironmentObject <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> counter: Counter\n\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        Button(<span style=\"color:#e6db74\">&#34;Increment&#34;<\/span>, action: { counter.value <span style=\"color:#f92672\">+=<\/span> <span style=\"color:#ae81ff\">1<\/span> })\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/enviroment-object-xcode-playground.png\" width=\"600\" height=\"439\" alt=\"Xcode Playground with EnvironmentObject example\">\n"},{"title":"How to format Swift source code using SwiftFormat","link":"https:\/\/kamil.id\/2021\/04\/11\/how-to-format-swift-source\/","pubDate":"Sun, 11 Apr 2021 13:04:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/04\/11\/how-to-format-swift-source\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-format-swift-source-code-using-swiftformat.png\" width=\"600\" height=\"360\" alt=\"How to format Swift source code using SwiftFormat\">\n<p>Command + I is a very commonly used Xcode shortcut. It is used to fix the indentation of the selected code part. But it does no more than that. What&rsquo;s worst, it adds four spaces (or one tab if you use it for indentation) to empty lines. This article will learn how to install, configure and use a third-party command-line application called SwiftFormat for better Swift source code formatting.<\/p>\n<p><a href=\"https:\/\/github.com\/nicklockwood\/SwiftFormat\">SwiftFormat<\/a> is an open-source project created and maintained by Nick Lockwood - creator of a few famous and commonly used iOS libraries. It formats your code using more than 50 rules, which you can turn off and turn on individually. If you follow just the basic code formatting principles, you can be sure that SwiftFormat will handle the rest, giving you well-formatted code.<\/p>\n<p>You can install SwiftFormat using one of the provided <a href=\"https:\/\/github.com\/nicklockwood\/SwiftFormat#how-do-i-install-it\">methods<\/a>. I&rsquo;ll describe only one that is easiest for me - by using Homebrew.<\/p>\n<p>You have to first <a href=\"https:\/\/brew.sh\/\">install Homebrew<\/a> and then call<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-bash\" data-lang=\"bash\">brew install swiftformat\n<\/code><\/pre><\/div><p>And that&rsquo;s it. SwiftFormat is installed and ready to use.<\/p>\n<p>To run SwiftFormat over your project, go into the console to the project catalog and call:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-bash\" data-lang=\"bash\">swiftformat .\n<\/code><\/pre><\/div><p>The presented command will format all <code>.swift<\/code> files into this and all subdirectories. For the first run, <strong>I advise you to commit or stash your current code changes<\/strong>.<\/p>\n<p>If you go to <a href=\"https:\/\/github.com\/nicklockwood\/SwiftFormat#options\">documentation<\/a>, you will find that you can control different properties. You can specify them using the command line argument of the <code>.swiftformat<\/code> file placed in the same director.<\/p>\n<p>I like default settings, so the only thing I do is turn off formatting on some generated directories (like CoreData or Pods) and directly specify the Swift version. I made the <code>swiftformat.sh<\/code> file for this that looks similar to this one:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-bash\" data-lang=\"bash\"><span style=\"color:#75715e\">#!\/bin\/bash\n<\/span><span style=\"color:#75715e\"><\/span><span style=\"color:#75715e\"># Install swiftformat via brew first with `brew install swiftformat`<\/span>\n\nswiftformat . --swiftversion 5.3 --exclude Shared\/Resources,Shared\/Models\/CoreData --disable wrapMultilineStatementBraces\n<\/code><\/pre><\/div>"},{"title":"How to create your own property wrapper","link":"https:\/\/kamil.id\/2021\/04\/05\/how-to-create-your-own\/","pubDate":"Mon, 05 Apr 2021 14:19:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/04\/05\/how-to-create-your-own\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-create-own-property-wrapper.png\" width=\"600\" height=\"360\" alt=\"How to create own property wrapper\">\n<p>Swift (SwiftUI in particular) commonly uses property wrappers to make repeatable operations easier. For example, the @State is used for observing and storing view state, and @AppStorage to store app parameters using local persistence.<\/p>\n<blockquote>\n<p>Learn <a href=\"https:\/\/kamil.id\/2021\/01\/11\/how-to-access.html\">how to use AppStorage to access UserDefaults in SwiftUI<\/a>.<\/p>\n<\/blockquote>\n<p>But you are not limited to build-in property wrappers. You can make your property wrappers and add additional functionalities to struct and class properties (property wrappers are not supported at the top level).<\/p>\n<p>This article will learn how to build a super simple property wrapper that will print the current value when you read or write it. It can help debug, but the goal is to show you how custom property wrappers work.<\/p>\n<p>Property wrapper is a struct marked with <code>@propertyWrapper<\/code> attribute. It requires a <code>wrappedValue<\/code> property.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@propertyWrapper\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">CustomWrapper<\/span>&lt;Value&gt; {\n    <span style=\"color:#66d9ef\">var<\/span> wrappedValue: Value\n}\n<\/code><\/pre><\/div><p>That&rsquo;s it. You can now use your property wrapper on any property.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@CustomWrapper <span style=\"color:#66d9ef\">var<\/span> value = <span style=\"color:#ae81ff\">0<\/span>\n<\/code><\/pre><\/div><p>But in the current state, it doesn&rsquo;t do anything. Let&rsquo;s add some logic when the wrapped value is set or get.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@propertyWrapper\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Logged<\/span>&lt;Value&gt; {\n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> value: Value\n\n    <span style=\"color:#66d9ef\">init<\/span>(wrappedValue: Value) {\n        <span style=\"color:#66d9ef\">self<\/span>.value = wrappedValue\n    }\n\n    <span style=\"color:#66d9ef\">var<\/span> wrappedValue: Value {\n        <span style=\"color:#66d9ef\">get<\/span> {\n            print(<span style=\"color:#e6db74\">&#34;Value get: <\/span><span style=\"color:#e6db74\">\\(<\/span>value<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\n            <span style=\"color:#66d9ef\">return<\/span> value\n        }\n        <span style=\"color:#66d9ef\">set<\/span> {\n            print(<span style=\"color:#e6db74\">&#34;Value set: <\/span><span style=\"color:#e6db74\">\\(<\/span>newValue<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\n            value = newValue\n        }\n    }\n}\n<\/code><\/pre><\/div><p>When you try to read or change a given property, you will also see information about a current state on the console.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#75715e\">\/\/ Property wrappers are not supported on top level<\/span>\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Object<\/span> {\n    @Logged <span style=\"color:#66d9ef\">var<\/span> value = <span style=\"color:#ae81ff\">0<\/span>\n}\n\n<span style=\"color:#66d9ef\">var<\/span> object = Object()\n\nprint(<span style=\"color:#e6db74\">&#34;Value is equal to: <\/span><span style=\"color:#e6db74\">\\(<\/span>object.value<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\nprint(<span style=\"color:#e6db74\">&#34;---&#34;<\/span>)\nobject.value = <span style=\"color:#ae81ff\">100<\/span>\nprint(<span style=\"color:#e6db74\">&#34;---&#34;<\/span>)\nprint(<span style=\"color:#e6db74\">&#34;Value is equal to: <\/span><span style=\"color:#e6db74\">\\(<\/span>object.value<span style=\"color:#e6db74\">)<\/span><span style=\"color:#e6db74\">&#34;<\/span>)\n\n<span style=\"color:#75715e\">\/*\n<\/span><span style=\"color:#75715e\">Prints:\n<\/span><span style=\"color:#75715e\">Value get: 0\n<\/span><span style=\"color:#75715e\">Value is equal to: 0\n<\/span><span style=\"color:#75715e\">---\n<\/span><span style=\"color:#75715e\">Value set: 100\n<\/span><span style=\"color:#75715e\">---\n<\/span><span style=\"color:#75715e\">Value get: 100\n<\/span><span style=\"color:#75715e\">Value is equal to: 100\n<\/span><span style=\"color:#75715e\">*\/<\/span>\n<\/code><\/pre><\/div><p>Of course, the provided example is elementary, but property wrappers can be used in various cases. Some libraries help with <a href=\"https:\/\/github.com\/SvenTiigi\/ValidatedPropertyKit\">data validation<\/a> and simplify usage of <a href=\"https:\/\/github.com\/marksands\/BetterCodable\">codable<\/a>.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/simple-property-wrapper-xcode-playground.png\" width=\"600\" height=\"427\" alt=\"Simple property wrapper example - Xcode Playground\">\n"},{"title":"How to disable button in SwiftUI","link":"https:\/\/kamil.id\/2021\/03\/28\/how-to-disable-button-in\/","pubDate":"Sun, 28 Mar 2021 10:56:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/03\/28\/how-to-disable-button-in\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-disable-button-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to disable button in SwiftUI\">\n<p>In your SwiftUI applications, you will often use the Button view. This interactive control is used to build simple user inputs. But in this article, you will learn how to disable buttons.<\/p>\n<p>Think about a situation as follow - you have three different options, but some of them are only active when the toggle is true. You can hide inactive options using the <code>if<\/code> statement, but this will be counterintuitive for users. The &ldquo;Don&rsquo;t make me think&rdquo; principle assumes that users should know what&rsquo;s going on and not be surprised by UI. You can achieve it by just disabling that options.<\/p>\n<p>To <code>disable<\/code> a button, you should use the disabled view modifier. It takes a bool parameter, which, for example, can be taken from the state.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> disabled = <span style=\"color:#66d9ef\">true<\/span>\n\n<span style=\"color:#66d9ef\">var<\/span> body: some View {\n    Button(<span style=\"color:#e6db74\">&#34;Press me&#34;<\/span>, action: {})\n        .disabled(disabled)\n}\n<\/code><\/pre><\/div><p>You can use the <code>disabled<\/code> modifier on a view above buttons (<code>VStack<\/code>, for example). That way, you will apply it to all buttons (or other controls below).<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">VStack {\n    Button(<span style=\"color:#e6db74\">&#34;Press me 1&#34;<\/span>, action: {})\n    Button(<span style=\"color:#e6db74\">&#34;Press me 2&#34;<\/span>, action: {})\n    Button(<span style=\"color:#e6db74\">&#34;Press me 3&#34;<\/span>, action: {})\n}\n.disabled(<span style=\"color:#66d9ef\">true<\/span>)\n<\/code><\/pre><\/div><p><strong>Note<\/strong>: According to <a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/list\/disabled(_:)\">the documentation<\/a>, <code>disabled<\/code> from a view higher in scope takes precedence over disabled from lower views. But my experiments (you can find a link to the project below) show that priority has one that its parameter is set to <code>true<\/code> and order is not important.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/disable-button-xcode-example.png\" width=\"600\" height=\"376\" alt=\"Disable button Xcode Example\">\n"},{"title":"How to display a scrollable list using the List view","link":"https:\/\/kamil.id\/2021\/03\/13\/how-to-display-a-scrollable\/","pubDate":"Sat, 13 Mar 2021 22:08:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/03\/13\/how-to-display-a-scrollable\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-display-a-scrollable-list-using-the-list-view.png\" width=\"600\" height=\"360\" alt=\"How to display a scrollable list using the List view\">\n<p><code>List<\/code> view is a container that can present a scrollable list of views in SwiftUI. You can adjust its look, and it supports versatile actions and change its style depending on the platform. This article will learn how to use the List to display navigation links, data from an array and use ForEach and Section to display multi-dimensional data structures.<\/p>\n<h2 id=\"simple-list\">Simple List<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/lists-simple.png\" width=\"277\" height=\"600\" alt=\"Simple list\">\n<p>As always, SwiftUI creators made it easy to use API. You can display a basic <code>List<\/code> with only a few lines of code.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">List {\n    Text(<span style=\"color:#e6db74\">&#34;Identifiable List&#34;<\/span>)\n    Text(<span style=\"color:#e6db74\">&#34;Multi-Dimensional List&#34;<\/span>)\n    Text(<span style=\"color:#e6db74\">&#34;Inset Grouped List Style&#34;<\/span>)\n}\n<\/code><\/pre><\/div><p>Additionally, wrapping your items in List instead of <code>VStack<\/code> will make them scrollable. So, if there are more items that fit on the screen, they will still be accessible to users.<\/p>\n<p>You can use the List view to build the app navigation. When you wrap your <code>Texts<\/code> (or any other View) in <code>NavigationLink<\/code>, they will get an additional details arrow and, together with <code>NavigationView<\/code>, will handle switching between screens.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">NavigationView {\n    List {\n        NavigationLink(destination: IdentifiableList()) {\n            Text(<span style=\"color:#e6db74\">&#34;Identifiable List&#34;<\/span>)\n        }\n        NavigationLink(\n            destination: MultiDimensionalList()\n                 .navigationTitle(<span style=\"color:#e6db74\">&#34;Multi-Dimensional List&#34;<\/span>)\n        ) {\n            Text(<span style=\"color:#e6db74\">&#34;Multi-Dimensional List&#34;<\/span>)\n        }\n        NavigationLink(\n            destination: MultiDimensionalList()\n                .listStyle(InsetGroupedListStyle())\n                .navigationTitle(<span style=\"color:#e6db74\">&#34;Inset Grouped Style&#34;<\/span>)\n        ) {\n            Text(<span style=\"color:#e6db74\">&#34;Inset Grouped List Style&#34;<\/span>)\n        }\n    }\n    .navigationTitle(<span style=\"color:#e6db74\">&#34;Simple list&#34;<\/span>)\n}\n<\/code><\/pre><\/div><h2 id=\"identifiable-list\">Identifiable List<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/lists-identifiable.png\" width=\"277\" height=\"600\" alt=\"Identifiable list\">\n<p>When using lists, you usually have an array of data. One of the <code>List<\/code> initializers can get that data and generates a list of items. It will handle rendering only visible entities at a given moment which is essential for application memory usage.<\/p>\n<p>The data that you provide must conform to the Identifiable protocol. It&rsquo;s straightforward to achieve. Your struct must have an id property that conforms to <code>Hashable<\/code>. <code>String<\/code> or <code>UUID<\/code> type is usually perfect for this.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Continent<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: UUID = UUID()\n    <span style=\"color:#66d9ef\">let<\/span> name: String\n}\n\n<span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">let<\/span> continents = [\n    Continent(name: <span style=\"color:#e6db74\">&#34;Asia&#34;<\/span>),\n    Continent(name: <span style=\"color:#e6db74\">&#34;Africa&#34;<\/span>),\n    Continent(name: <span style=\"color:#e6db74\">&#34;North America&#34;<\/span>),\n    Continent(name: <span style=\"color:#e6db74\">&#34;South America&#34;<\/span>),\n    Continent(name: <span style=\"color:#e6db74\">&#34;Antarctica&#34;<\/span>),\n    Continent(name: <span style=\"color:#e6db74\">&#34;Europe&#34;<\/span>),\n    Continent(name: <span style=\"color:#e6db74\">&#34;Australia&#34;<\/span>)\n]\n<\/code><\/pre><\/div><p>With struct declared like the one above, you can easily display an array of structs with just three lines:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">List(continents) {\n    Text($0.name)\n}\n<\/code><\/pre><\/div><h2 id=\"multi-dimensional-list\">Multi-dimensional List<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/lists-multidimensional.png\" width=\"277\" height=\"600\" alt=\"Multi-Dimensional List\">\n<p>With the support of two other views - <code>ForEach<\/code> and <code>Section<\/code> you can create a stunning two-dimensional list. For this example, I added an array of animals to a <code>Continent<\/code> struct.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Continent<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: UUID = UUID()\n    <span style=\"color:#66d9ef\">let<\/span> name: String\n    <span style=\"color:#66d9ef\">let<\/span> animals: [Animal]\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Animal<\/span>: Identifiable {\n    <span style=\"color:#66d9ef\">let<\/span> id: UUID = UUID()\n    <span style=\"color:#66d9ef\">let<\/span> name: String\n}\n<\/code><\/pre><\/div><p>When you build your example structure, what is only need to iterate over items. The <code>Section<\/code> view displays a header, and objects in each behave like normal list cells.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">List {\n    ForEach(continents) { continent <span style=\"color:#66d9ef\">in<\/span>\n        Section(header: Text(continent.name)) {\n            ForEach(continent.animals) { animal <span style=\"color:#66d9ef\">in<\/span>\n                Text(animal.name)\n            }\n        }\n    }\n}\n<\/code><\/pre><\/div><h2 id=\"inset-grouped-list-style\">Inset Grouped List Style<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/lists-inset-grouped-style.png\" width=\"277\" height=\"600\" alt=\"Multi-Dimensional List\">\n<p>This article covers just an iceberg of list features, but I want to mention one more element that, with just one line, will take your design to the next level. I&rsquo;m talking about the <code>listStyle<\/code> modifier. With one line:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">.listStyle(InsetGroupedListStyle())\n<\/code><\/pre><\/div><p>You may change a list from the previous section to the one visible at the start of this one.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/lists-xcode-project.png\" width=\"600\" height=\"380\" alt=\"Xcode Project to test presented examples\">\n"},{"title":"How to display UIKit view in SwiftUI using UIViewRepresentable","link":"https:\/\/kamil.id\/2021\/02\/28\/how-to-display-uikit-view\/","pubDate":"Sun, 28 Feb 2021 22:16:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/02\/28\/how-to-display-uikit-view\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-display-uikit-view-in-swiftui-using-uiviewrepresentable.png\" width=\"600\" height=\"360\" alt=\"How to display UIKit view in SwiftUI using UIViewRepresentable\">\n<p>One of the biggest arguments in favor of using SwiftUI in production apps is the interoperability of UIKit. If you have a problem with achieving something with pure SwiftUI, you can always use <code>UIViewRepresentable<\/code> to wrap UIKit view and put it in the SwiftUI app only in dozen lines of code. How to do this? Read further.<\/p>\n<p>This article will teach you how to wrap <code>UITextView<\/code> into <code>UIViewRepresentable<\/code> protocol, with the <code>Coordinator<\/code> notifying your app when the text changes.<\/p>\n<p>I used an elementary example with <code>UITextView<\/code>, but creating UIViewRepresentable will always look very similar. First, you have to wrap your view in the protocol and then build a <code>Coordinator<\/code> to handle UIKit delegate and data source methods.<\/p>\n<h2 id=\"uiviewrepresentable\">UIViewRepresentable<\/h2>\n<p>UIViewRepresentable protocol requires confirmation for two methods.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">associatedtype UIViewType: UIView\n<span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeUIView<\/span>(context: <span style=\"color:#66d9ef\">Self<\/span>.Context) -&gt; <span style=\"color:#66d9ef\">Self<\/span>.UIViewType\n<span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">updateUIView<\/span>(<span style=\"color:#66d9ef\">_<\/span> uiView: <span style=\"color:#66d9ef\">Self<\/span>.UIViewType, context: <span style=\"color:#66d9ef\">Self<\/span>.Context)\n<\/code><\/pre><\/div><p>The <code>makeUIView<\/code> method should create a UIKit view and returns it for SwiftUI to handle. SwiftUI calls this method when the view is created. Then <code>updateUIView<\/code> is called when your view should be updated. Both methods bring you a <code>UIViewRepresentableContext<\/code> struct which you can use to get <code>Coordinator<\/code> or various environment values.<\/p>\n<p>A simple implementation for <code>UITextView<\/code> may look like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TextView<\/span>: UIViewRepresentable {\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeUIView<\/span>(context: Context) -&gt; UITextView {\n        <span style=\"color:#66d9ef\">let<\/span> view = UITextView()\n        view.layer.borderWidth = <span style=\"color:#ae81ff\">1<\/span>\n        view.layer.borderColor = UIColor.systemGray.cgColor\n        view.layer.cornerRadius = <span style=\"color:#ae81ff\">8<\/span>\n        <span style=\"color:#66d9ef\">return<\/span> view\n    }\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">updateUIView<\/span>(<span style=\"color:#66d9ef\">_<\/span> uiView: UITextView, context: Context) {\n        \n    }\n}\n<\/code><\/pre><\/div><p>When used in SwiftUI, the code above will display a <code>UITextView<\/code> with a border for better visibility.<\/p>\n<p>But you may want to provide the initial text value and refresh text if it changes from outside. For this, you should use a <code>Binding<\/code> property wrapper and <code>updateUIView<\/code>.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TextView<\/span>: UIViewRepresentable {\n    @Binding <span style=\"color:#66d9ef\">var<\/span> text: String <span style=\"color:#75715e\">\/\/ NEW<\/span>\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeUIView<\/span>(context: Context) -&gt; UITextView {\n        <span style=\"color:#66d9ef\">let<\/span> view = UITextView()\n        view.layer.borderWidth = <span style=\"color:#ae81ff\">1<\/span>\n        view.layer.borderColor = UIColor.systemGray.cgColor\n        view.layer.cornerRadius = <span style=\"color:#ae81ff\">8<\/span>\n        <span style=\"color:#66d9ef\">return<\/span> view\n    }\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">updateUIView<\/span>(<span style=\"color:#66d9ef\">_<\/span> uiView: UITextView, context: Context) {\n        uiView.text = text <span style=\"color:#75715e\">\/\/ NEW<\/span>\n    }\n}\n<\/code><\/pre><\/div><p>You can use this view in SwiftUI as follow:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text: String = <span style=\"color:#e6db74\">&#34;Initial text&#34;<\/span>\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        TextView(text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n    }\n}\n<\/code><\/pre><\/div><h2 id=\"coordinator\">Coordinator<\/h2>\n<p>What you saw is just half of the equation. You will also need to know when <code>UITextView<\/code> content did changed. For this, <code>UIViewRepresentable<\/code> offers an optional method:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"> associatedtype Coordinator = Void\n <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeCoordinator<\/span>() -&gt; <span style=\"color:#66d9ef\">Self<\/span>.Coordinator\n<\/code><\/pre><\/div><p>that you can implement and along with Binding property used to inform SwiftUI about current text <code>UITextView<\/code>.<\/p>\n<p>First, start with the <code>makeCoordinator<\/code> method. This method can return any entity, no matter struct or class.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeCoordinator<\/span>() -&gt; Coordinator {\n    Coordinator(text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n}\n<\/code><\/pre><\/div><p>Your <code>Coordinator<\/code> object will receive the <code>text<\/code> variable as a Binding (returned with <code>$<\/code> syntactic sugar).<\/p>\n<p>Ok, now you can go to <code>Coordinator<\/code> class implementation.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">class<\/span> <span style=\"color:#a6e22e\">Coordinator<\/span>: NSObject, UITextViewDelegate {\n    @Binding <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text: String\n\n    <span style=\"color:#66d9ef\">init<\/span>(text: Binding&lt;String&gt;) {\n        <span style=\"color:#66d9ef\">self<\/span>._text = text\n    }\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">textViewDidChange<\/span>(<span style=\"color:#66d9ef\">_<\/span> textView: UITextView) {\n        text = textView.text\n    }\n}\n<\/code><\/pre><\/div><p>As you can see, it implements <code>UITextViewDelegate<\/code> protocol (and <code>NSObject<\/code> required by it), and in <code>textViewDidChange<\/code>, it updates the text variable. In this example, the <code>Coordinator<\/code> is a class, so it needs an <code>init<\/code> method that sets <code>Binding&lt;String&gt;<\/code> to local property wrapper using <code>_text<\/code> syntax.<\/p>\n<p>There is one puzzle missing. You have to connect your <code>Coordinator<\/code> with <code>UITextView<\/code>. Do this in <code>makeUIView<\/code>, but don&rsquo;t create it there. Use the one provided in context.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeUIView<\/span>(context: Context) -&gt; UITextView {\n    <span style=\"color:#66d9ef\">let<\/span> view = UITextView()\n    view.delegate = context.coordinator <span style=\"color:#75715e\">\/\/ NEW<\/span>\n    view.layer.borderWidth = <span style=\"color:#ae81ff\">1<\/span>\n    view.layer.borderColor = UIColor.systemGray.cgColor\n    view.layer.cornerRadius = <span style=\"color:#ae81ff\">8<\/span>\n    <span style=\"color:#66d9ef\">return<\/span> view\n}\n<\/code><\/pre><\/div><h2 id=\"wrap-up\">Wrap up<\/h2>\n<p>As you can see, using UIKit views in SwiftUI is easy. You can check the complete code, along with an example of how to use it with the State property wrapper below.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    @State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text: String = <span style=\"color:#e6db74\">&#34;Initial text&#34;<\/span>\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        TextView(text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n    }\n}\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">TextView<\/span>: UIViewRepresentable {\n    @Binding <span style=\"color:#66d9ef\">var<\/span> text: String\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeUIView<\/span>(context: Context) -&gt; UITextView {\n        <span style=\"color:#66d9ef\">let<\/span> view = UITextView()\n        view.delegate = context.coordinator\n        view.layer.borderWidth = <span style=\"color:#ae81ff\">1<\/span>\n        view.layer.borderColor = UIColor.systemGray.cgColor\n        view.layer.cornerRadius = <span style=\"color:#ae81ff\">8<\/span>\n        <span style=\"color:#66d9ef\">return<\/span> view\n    }\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">makeCoordinator<\/span>() -&gt; Coordinator {\n        Coordinator(text: <span style=\"color:#960050;background-color:#1e0010\">$<\/span>text)\n    }\n\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">updateUIView<\/span>(<span style=\"color:#66d9ef\">_<\/span> uiView: UITextView, context: Context) {\n        uiView.text = text\n    }\n\n    <span style=\"color:#66d9ef\">class<\/span> <span style=\"color:#a6e22e\">Coordinator<\/span>: NSObject, UITextViewDelegate {\n        @Binding <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> text: String\n\n        <span style=\"color:#66d9ef\">init<\/span>(text: Binding&lt;String&gt;) {\n            <span style=\"color:#66d9ef\">self<\/span>._text = text\n        }\n\n        <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">textViewDidChange<\/span>(<span style=\"color:#66d9ef\">_<\/span> textView: UITextView) {\n            text = textView.text\n        }\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/uiviewrepresentable-xcode-example-project.png\" width=\"600\" height=\"385\" alt=\"UIViewRepresentable Xcode example project\">\n"},{"title":"How to add rounded corners in SwiftUI","link":"https:\/\/kamil.id\/2021\/02\/21\/how-to-add-rounded-corners\/","pubDate":"Sun, 21 Feb 2021 13:12:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/02\/21\/how-to-add-rounded-corners\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-add-rounded-corners-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to add rounded corners in SwiftUI\">\n<p>Rounded corners, like many other things in SwiftUI, can be added in few different ways. In this article, you will learn the simples one and one more sophisticated that you may find helpful in some circumstances. Let&rsquo;s start.<\/p>\n<h2 id=\"viewmodifier\">ViewModifier<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/rounded-corners-fill.png\" width=\"260\" height=\"83\" alt=\"cornerRadius modifier effect\">\n<p>The easiest way to add rounded corners to any view is by using the cornerRadius modifier. Of course, you have to add background to see the effect of this modifier. You can achieve the example above with these five lines of code:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n    .font(.largeTitle)\n    .padding()\n    .background(Color.green)\n    .cornerRadius(<span style=\"color:#ae81ff\">16<\/span>)\n<\/code><\/pre><\/div><p>The <code>cornerRadius<\/code> modifier supports two parameters. The first unnamed one is <code>radius<\/code>, and the second one is <code>antialiased<\/code>, which is by default set to true.<\/p>\n<h2 id=\"shape\">Shape<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/rounded-corners-fill.png\" width=\"260\" height=\"83\" alt=\"RoundedRectangle effect\">\n<p>Instead of using cornerRadius, you can create a more sophisticated view by using ZStack.<\/p>\n<blockquote>\n<p>I used a similar solution to <a href=\"https:\/\/kamil.id\/2021\/01\/31\/how-to-use.html\">create chat bubbles<\/a>.<\/p>\n<\/blockquote>\n<p>A solution like this isn&rsquo;t probably recommended to add only a background with rounded corners, but you may find it useful to start playing with advanced views. This solution begins with the <code>RoundedRectangle<\/code> shape. Since the <code>Shape<\/code> struct is also a View, you can use it as a base for your creations. Putting <code>RoundedRectangle<\/code> into <code>ZStack<\/code>, just above your given view, will create a rounded background effect.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">ZStack {\n    RoundedRectangle(cornerRadius: <span style=\"color:#ae81ff\">16<\/span>)\n        .foregroundColor(.green)\n    Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n        .font(.largeTitle)\n        .padding()\n}\n<\/code><\/pre><\/div><p>When creating the <code>RoundedRectangle<\/code> struct, you can provide a <code>cornerRadius<\/code> parameter.<\/p>\n<h2 id=\"overlay\">Overlay<\/h2>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/rounded-corners-border.png\" width=\"260\" height=\"81\" alt=\"strokeBorder and RoundedRectangle effect\">\n<p>There is also a third solution, often used to create borders. This solution uses the <code>overlay<\/code> to display a view above another view. If you use it for the rounded background, it will cover your creation. But it will work perfectly for borders.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">    Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n        .font(.largeTitle)\n        .padding()\n        .overlay(\n            RoundedRectangle(cornerRadius: <span style=\"color:#ae81ff\">16<\/span>)\n                .strokeBorder()\n                .foregroundColor(.green)\n        )\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/rounded-corners-xcode-playground.png\" width=\"600\" height=\"388\" alt=\"Xcode Playground with rounded corners examples\">\n"},{"title":"How to style Text view in SwiftUI","link":"https:\/\/kamil.id\/2021\/02\/15\/how-to-style-text-view\/","pubDate":"Mon, 15 Feb 2021 17:27:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/02\/15\/how-to-style-text-view\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-style-text-view-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to style Text view in SwiftUI\">\n<p>You can style SwiftUI Text views with a bunch of dedicated ViewModifiers. Learn about them in this article.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/text-styles.png\" width=\"254\" height=\"520\" alt=\"Text styles covered in this article\">\n<h2 id=\"how-to-apply-italic-text-style\">How to apply italic text style?<\/h2>\n<p>You can switch the font to cursive using the <code>italic<\/code> modifier.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;italic&#34;<\/span>)\n    .italic()\n<\/code><\/pre><\/div><h2 id=\"how-to-apply-bold-text-style\">How to apply bold text style?<\/h2>\n<p>The <code>bold<\/code> view modifier will make the displayed text bolder.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;bold&#34;<\/span>)\n    .bold()\n<\/code><\/pre><\/div><p>Of course, you can stack these two modifiers to create an italic and bold typeface.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;bold &amp; italic&#34;<\/span>)\n    .bold()\n    .italic()\n<\/code><\/pre><\/div><h2 id=\"how-to-change-font-weight\">How to change font weight?<\/h2>\n<p>If you want to set your font to something different than bold, you can use the <code>weight<\/code> modifier.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;fontWeight heavy&#34;<\/span>)\n    .fontWeight(.heavy)\n<\/code><\/pre><\/div><h2 id=\"how-to-change-the-font\">How to change the font?<\/h2>\n<p>The <code>font<\/code> modifier is applicable if you want to change more text parameters. There are predefined fonts that you can use for various elements of the app. In the example below <code>title<\/code> font is set.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;font .title&#34;<\/span>)\n    .font(.title)\n<\/code><\/pre><\/div><p>You can create own Font <code>struct<\/code> to pick different font family, size or weight.<\/p>\n<h2 id=\"how-to-strikethrough-a-text\">How to strikethrough a text?<\/h2>\n<p>There are two versions of the <code>strikethrough<\/code> modifier. One without argument that displays a line in the foreground color:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;strikethrough&#34;<\/span>)\n    .strikethrough()\n<\/code><\/pre><\/div><p>The second one has an <code>active<\/code> parameter and color option where you can control a strikethrough color.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;strikethrough color&#34;<\/span>)\n    .strikethrough(<span style=\"color:#66d9ef\">true<\/span>, color: .red)\n<\/code><\/pre><\/div><h2 id=\"how-to-underline-a-text\">How to underline a text?<\/h2>\n<p>Instead of strikethrough, you may want to underline a text. API for this is very similar. More straightforward underline modifier takes foreground color value:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;underline&#34;<\/span>)\n    .underline()\n<\/code><\/pre><\/div><p>And more advanced has active and color parameters:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;underline color&#34;<\/span>)\n    .underline(<span style=\"color:#66d9ef\">true<\/span>, color: .red)\n<\/code><\/pre><\/div><h2 id=\"how-to-change-the-text-color\">How to change the text color?<\/h2>\n<p>Text view content color can be changed using the <code>foregroundColor<\/code> modifier.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;foregroundColor&#34;<\/span>)\n    .foregroundColor(.red)\n<\/code><\/pre><\/div><blockquote>\n<p>Learn <a href=\"https:\/\/swiftwombat.com\/how-to-create-custom-viewmodifier\/\">how to colorize text using a gradient<\/a>.<\/p>\n<\/blockquote>\n<h2 id=\"how-to-change-the-text-view-background-color\">How to change the Text view background color?<\/h2>\n<p>The background of any view can be applied using the <code>background<\/code> modifier. Since SwiftUI Color is also a view, you can use it to apply a color background to the text below.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;background&#34;<\/span>)\n    .background(Color.red)\n<\/code><\/pre><\/div><h2 id=\"how-to-change-the-baseline-offset-of-text\">How to change the baseline offset of text?<\/h2>\n<p>The baseline can be used to display your text above or below the normal text baseline. The <code>baselineOffset<\/code> view modifier accept positive and negative numbers. You will often use it with Text view concatenation with <code>+<\/code> sign.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;baseline &#34;<\/span>)\n   <span style=\"color:#f92672\">+<\/span> Text(<span style=\"color:#e6db74\">&#34;Off&#34;<\/span>)\n       .baselineOffset(<span style=\"color:#ae81ff\">10<\/span>)\n   <span style=\"color:#f92672\">+<\/span> Text(<span style=\"color:#e6db74\">&#34;set&#34;<\/span>)\n       .baselineOffset(<span style=\"color:#f92672\">-<\/span><span style=\"color:#ae81ff\">10<\/span>)\n<\/code><\/pre><\/div><h2 id=\"how-to-adjust-kerning\">How to adjust kerning?<\/h2>\n<p>You can adjust kerning (the distance between a pair of letters) with the kerning modifier.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;kerning kerning kerning&#34;<\/span>)\n    .kerning(<span style=\"color:#ae81ff\">1.2<\/span>)\n<\/code><\/pre><\/div><h2 id=\"how-to-adjust-tracking\">How to adjust tracking?<\/h2>\n<p>Tracking delivers a similar effect to kerning, but it adds distance between each character, which means that ligatures will also be separated.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;tracking tracking tracking&#34;<\/span>)\n    .tracking(<span style=\"color:#ae81ff\">1.2<\/span>)\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/text-view-styles-xcode-example.png\" width=\"600\" height=\"388\" alt=\"Text styles examples in Xcode Playground\">\n"},{"title":"How to display swipeable pages in SwiftUI","link":"https:\/\/kamil.id\/2021\/02\/05\/how-to-display-swipeable-pages\/","pubDate":"Fri, 05 Feb 2021 21:00:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/02\/05\/how-to-display-swipeable-pages\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-display-swipeable-pages-in-swiftui.png\" width=\"600\" height=\"360\" alt=\"How to display swipeable pages in SwiftUI\">\n<p>Swipeable pages, often used for application onboardings, can be easily made using SwiftUI <code>TabView<\/code>. In this tutorial, you will learn how to create a view like the one presented in the (low-quality) GIF below.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/swipeable-pages.gif\" width=\"300\" height=\"300\" alt=\"Slideable pages preview animation\">\n<p>When you see <code>TabView's<\/code> name, the first you may think is a tab bar navigation like the one you can make using <code>UITabBarController<\/code>. It is its first and most common usage, but TabView can be styled to look like <code>UIPageViewController<\/code>.<\/p>\n<p><code>TabView<\/code> has a straightforward API. Basic usage of it looks like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">TabView {\n    Text(<span style=\"color:#e6db74\">&#34;Page 1&#34;<\/span>)\n    Text(<span style=\"color:#e6db74\">&#34;Page 2&#34;<\/span>)\n    Text(<span style=\"color:#e6db74\">&#34;Page 3&#34;<\/span>)\n}\n<\/code><\/pre><\/div><p>You list all tabs\/pages using view builder. It&rsquo;s often used with a specification of images and titles placed on the tab bar items:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">TabView {\n    Text(<span style=\"color:#e6db74\">&#34;Page 1&#34;<\/span>)\n        .tabItem {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;1.square.fill&#34;<\/span>)\n            Text(<span style=\"color:#e6db74\">&#34;Page 1&#34;<\/span>)\n        }\n    Text(<span style=\"color:#e6db74\">&#34;Page 2&#34;<\/span>)\n        .tabItem {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;2.square.fill&#34;<\/span>)\n            Text(<span style=\"color:#e6db74\">&#34;Page 2&#34;<\/span>)\n        }\n    Text(<span style=\"color:#e6db74\">&#34;Page 3&#34;<\/span>)\n        .tabItem {\n            Image(systemName: <span style=\"color:#e6db74\">&#34;3.square.fill&#34;<\/span>)\n            Text(<span style=\"color:#e6db74\">&#34;Page 3&#34;<\/span>)\n        }\n}\n<\/code><\/pre><\/div><p>To change the tab bar to page view, you have to set a different style using <code>tabViewStyle<\/code> modifier:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">.tabViewStyle(PageTabViewStyle())\n<\/code><\/pre><\/div><p>To achieve the effect from GIF, you have to create a Page view first:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">SwiftUI<\/span>\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">Page<\/span>: View {\n    <span style=\"color:#66d9ef\">let<\/span> title: String\n    <span style=\"color:#66d9ef\">let<\/span> image: String\n    <span style=\"color:#66d9ef\">let<\/span> color: Color\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        VStack {\n            Image(image)\n                .resizable()\n                .scaledToFit()\n                .padding()\n            Text(title)\n                .bold()\n                .font(.title)\n                .foregroundColor(.white)\n                .padding(.bottom, <span style=\"color:#ae81ff\">32<\/span>)\n        }\n        .frame(maxWidth: .infinity, maxHeight: .infinity)\n        .background(color)\n        .cornerRadius(<span style=\"color:#ae81ff\">16<\/span>)\n        .padding()\n    }\n}\n<\/code><\/pre><\/div><p>and then configure TabView as follow:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">SwiftUI<\/span>\n\n<span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView<\/span>: View {\n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        TabView {\n            Page(\n                title: <span style=\"color:#e6db74\">&#34;Wombat&#34;<\/span>,\n                image: <span style=\"color:#e6db74\">&#34;wombat&#34;<\/span>,\n                color: Color(hex: <span style=\"color:#ae81ff\">0xF8CF3C<\/span>)\n            )\n            Page(\n                title: <span style=\"color:#e6db74\">&#34;Koala&#34;<\/span>,\n                image: <span style=\"color:#e6db74\">&#34;koala&#34;<\/span>,\n                color: Color(hex: <span style=\"color:#ae81ff\">0xF6B6AC<\/span>)\n            )\n            Page(\n                title: <span style=\"color:#e6db74\">&#34;Platypus&#34;<\/span>,\n                image: <span style=\"color:#e6db74\">&#34;platypus&#34;<\/span>,\n                color: Color(hex: <span style=\"color:#ae81ff\">0xF26E64<\/span>)\n            )\n        }\n        .tabViewStyle(PageTabViewStyle())\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/swipeable-pages-xcode-playground.png\" width=\"600\" height=\"352\" alt=\"Swipeable pages Xcode project template\">\n"},{"title":"How to use ZStack to create a chat bubble","link":"https:\/\/kamil.id\/2021\/01\/31\/how-to-use-zstack-to\/","pubDate":"Sun, 31 Jan 2021 12:58:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/01\/31\/how-to-use-zstack-to\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-use-zstack-to-create-a-chat-bubble.png\" width=\"600\" height=\"360\" alt=\"How to use ZStack to create a chat bubble\">\n<p><code>ZStack<\/code> is one of the basic building blocks of SwiftUI applications. Along with <code>HStack<\/code> and <code>VStack<\/code>, you will use them frequently. This article will explain what <code>ZStack<\/code> is and how to use it to build a crucial part of every chat UI - a chat bubble.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/ff08a7ad3c.png\" width=\"328\" height=\"314\" alt=\"Chat bubbles example\">\n<p>So what is this view with the strange name <code>ZStack<\/code>? It&rsquo;s a view that arranges its children one into another\/overlays them. In 3D space, we usually mark the third direction <code>z<\/code> along <code>x<\/code> and <code>y<\/code>.<\/p>\n<p><code>ZStack<\/code> syntax is very similar to <code>HStack<\/code> and <code>VStack<\/code>.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">ZStack {\n    Circle()\n        .foregroundColor(.green)\n    Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n}\n<\/code><\/pre><\/div><p>Additionally, you can provide an alignment parameter that controls the view position on a horizontal and vertical axis.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">ZStack(\n    alignment: Alignment(horizontal: .leading, vertical: .top)\n) {\n    Circle()\n        .foregroundColor(.green)\n    Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n }\n<\/code><\/pre><\/div><p>There is one view modifier that you need to know to complete this task. It&rsquo;s called a <code>layoutPriority<\/code>, and by providing a <code>Double<\/code> value for it, you can control the importance of views when the stack will layout them. By default, each has a priority set to zero. Set it to a higher value, and it will be authoritative when the stack calculates its frame.<\/p>\n<p>You may wonder why this is important. To make a chat bubble, you have to use <code>Image<\/code> view as a background with <code>resizable<\/code> modifier.<\/p>\n<blockquote>\n<p>Learn more about <a href=\"https:\/\/swiftwombat.com\/how-to-control-swiftui-image-resize-zones-with-capinsets\/\">resizable and how to control Image resize zones with it<\/a><\/p>\n<\/blockquote>\n<p>Resizable means that it will try to take all available space, but you want the background to fit the given text. It is a point where you should use <code>layoutPriority<\/code>.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">ZStack {\n    Image(<span style=\"color:#e6db74\">&#34;bubble&#34;<\/span>)\n        .resizable(capInsets: EdgeInsets(top: <span style=\"color:#ae81ff\">39<\/span>, leading: <span style=\"color:#ae81ff\">49<\/span>, bottom: <span style=\"color:#ae81ff\">39<\/span>, trailing: <span style=\"color:#ae81ff\">49<\/span>))\n        .renderingMode(.template)\n        .foregroundColor(.blue)\n     Text(<span style=\"color:#e6db74\">&#34;Did you hear about the Swift Wombat website?&#34;<\/span>)\n        .foregroundColor(.white)\n        .padding(.horizontal, <span style=\"color:#ae81ff\">16<\/span>)\n        .padding(.vertical)\n        .layoutPriority(<span style=\"color:#ae81ff\">1<\/span>)\n}\n<\/code><\/pre><\/div><p>That way, the <code>Text<\/code> view will have a layout priority, and the <code>Image<\/code> will adjust to its size.<\/p>\n<p>In the Xcode Playground example linked at the bottom of this article, you will find full code that will adjust the color and orientation of bubbles to distinguish messages that we send and receive.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/chat-bubble-xcode-playground.png\" width=\"600\" height=\"347\" alt=\"Chat bubble Xcode Playground\">\n"},{"title":"How to apply text modifiers based on a view state","link":"https:\/\/kamil.id\/2021\/01\/28\/how-to-apply-text-modifiers\/","pubDate":"Thu, 28 Jan 2021 19:14:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/01\/28\/how-to-apply-text-modifiers\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-apply-text-modifiers-based-on-a-view-state.png\" width=\"600\" height=\"360\" alt=\"How to apply text modifiers based on a view state\">\n<p>I saw the &ldquo;How to optionally make a Text italic?&rdquo; question on Reddit, and I thought it would be good material for a short article. From this tutorial, you will learn how to prepare a conditional italic modifier. Additionally, you will find out how to make more generic modifiers to control every Text&rsquo;s properties.<\/p>\n<p>So, let&rsquo;s start with italic. Let&rsquo;s assume that you have a @State property wrapper that looks like this one:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@State <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">var<\/span> isItalic = <span style=\"color:#66d9ef\">true<\/span>\n<\/code><\/pre><\/div><p>You can use the <code>if ... else ...<\/code> statement to control which version of Text is displayed.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">if<\/span> isItalic {\n    Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n        .italic()\n} <span style=\"color:#66d9ef\">else<\/span> {\n    Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n}\n<\/code><\/pre><\/div><p>This way, you have to repeat a code, which you should try to avoid.\nSome text modifiers (<a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/text\/strikethrough(_:color:)\">strikethrough for example<\/a>) have an <code>active<\/code> parameter, but not <code>italic<\/code>. You can easily create that with this extension:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">SwiftUI<\/span>\n\n<span style=\"color:#66d9ef\">extension<\/span> <span style=\"color:#a6e22e\">Text<\/span> {\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">italic<\/span>(<span style=\"color:#66d9ef\">_<\/span> active: Bool) -&gt; Text {\n        <span style=\"color:#66d9ef\">guard<\/span> active <span style=\"color:#66d9ef\">else<\/span> { <span style=\"color:#66d9ef\">return<\/span> <span style=\"color:#66d9ef\">self<\/span> }\n        <span style=\"color:#66d9ef\">return<\/span> italic()\n    }\n}\n<\/code><\/pre><\/div><p>And this alone will be an answer to the question from the first paragraph. But what if you want to handle also bold or font modifiers?\nYou can iterate at the solution above and add an additional modifier to the Text extension.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">SwiftUI<\/span>\n\n<span style=\"color:#66d9ef\">extension<\/span> <span style=\"color:#a6e22e\">Text<\/span> {\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">active<\/span>(\n        <span style=\"color:#66d9ef\">_<\/span> active: Bool,\n        <span style=\"color:#66d9ef\">_<\/span> modifier: (Text) -&gt; Text\n    ) -&gt; Text {\n        <span style=\"color:#66d9ef\">guard<\/span> active <span style=\"color:#66d9ef\">else<\/span> { <span style=\"color:#66d9ef\">return<\/span> <span style=\"color:#66d9ef\">self<\/span> }\n        <span style=\"color:#66d9ef\">return<\/span> modifier(<span style=\"color:#66d9ef\">self<\/span>)\n    }\n}\n<\/code><\/pre><\/div><p>It is a bit harder to read. This function takes two arguments. One is the active state that controls if modifier is applied on not, and the second one is a function - which gets a Text struct and returns its modified version. You can use it like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n    .active(isTitle, { $0.font(.title) })\n<\/code><\/pre><\/div><p>For functions without arguments, you may prepare another extension:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">SwiftUI<\/span>\n\n<span style=\"color:#66d9ef\">extension<\/span> <span style=\"color:#a6e22e\">Text<\/span> {\n    <span style=\"color:#66d9ef\">func<\/span> <span style=\"color:#a6e22e\">active<\/span>(\n        <span style=\"color:#66d9ef\">_<\/span> active: Bool,\n        <span style=\"color:#66d9ef\">_<\/span> modifier: (Text) -&gt; () -&gt; Text\n    ) -&gt; Text {\n        <span style=\"color:#66d9ef\">guard<\/span> active <span style=\"color:#66d9ef\">else<\/span> { <span style=\"color:#66d9ef\">return<\/span> <span style=\"color:#66d9ef\">self<\/span> }\n        <span style=\"color:#66d9ef\">return<\/span> modifier(<span style=\"color:#66d9ef\">self<\/span>)()\n    }\n}\n<\/code><\/pre><\/div><p>With it, you will be able to apply italic or bold even quicker:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">Text(<span style=\"color:#e6db74\">&#34;Swift Wombat&#34;<\/span>)\n    .active(isItalic, Text.italic)\n    .active(isBold, Text.bold)\n<\/code><\/pre><\/div><p>Note the capital case of the struct name <code>Text<\/code> in that version.<\/p>\n<img src=\"https:\/\/kamil.id\/uploads\/2024\/active-text-modifier-example-xcode-playground.png\" width=\"600\" height=\"406\" alt=\"Active text modifier example Xcode Playground\">\n"},{"title":"How to store a Date using AppStorage","link":"https:\/\/kamil.id\/2021\/01\/25\/how-to-store-a-date\/","pubDate":"Mon, 25 Jan 2021 10:29:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/01\/25\/how-to-store-a-date\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-store-a-date-using-appstorage.png\" width=\"600\" height=\"360\" alt=\"How to store a Date using AppStorage\">\n<p>By default, <code>@AppStorage<\/code> property wrapper supports <code>Int<\/code>, <code>String<\/code>, <code>Double<\/code>, <code>Data<\/code>, or <code>URL<\/code> values. You can store other classes\/structs\/enums if you make them conform to the <code>RawRepresentable<\/code> protocol. This tutorial will learn how to keep Dates in <code>UserDefaults<\/code> handled by <code>@AppStorage<\/code>.<\/p>\n<blockquote>\n<p>Learn <a href=\"https:\/\/kamil.id\/2021\/01\/11\/how-to-access.html\">basics of @AppStorage property wrapper<\/a>.<\/p>\n<\/blockquote>\n<p>If you write something like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\">@AppStorage(<span style=\"color:#e6db74\">&#34;savedDate&#34;<\/span>) <span style=\"color:#66d9ef\">var<\/span> date: Date = Date()\n<\/code><\/pre><\/div><p>the Swift compiler gives you an error because the <code>@AppStorage<\/code> property wrapper doesn&rsquo;t support Date type.<\/p>\n<p>But it supports objects that conform to <code>RawRepresentable<\/code> protocol, where that raw value is a String or Int. A proposed implementation may look like this:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">Foundation<\/span>\n\n<span style=\"color:#66d9ef\">extension<\/span> <span style=\"color:#a6e22e\">Date<\/span>: RawRepresentable {\n    <span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">static<\/span> <span style=\"color:#66d9ef\">let<\/span> formatter = ISO8601DateFormatter()\n    \n    <span style=\"color:#66d9ef\">public<\/span> <span style=\"color:#66d9ef\">var<\/span> rawValue: String {\n        Date.formatter.string(from: <span style=\"color:#66d9ef\">self<\/span>)\n    }\n    \n    <span style=\"color:#66d9ef\">public<\/span> <span style=\"color:#66d9ef\">init<\/span>?(rawValue: String) {\n        <span style=\"color:#66d9ef\">self<\/span> = Date.formatter.date(from: rawValue) ?? Date()\n    }\n}\n<\/code><\/pre><\/div><p>This code uses <code>ISO8601DateFormatter<\/code> to format a date to String and map it back. That formatter is static because creating and removing <code>DateFormatters<\/code> is an expensive operation. If you add the code above to your project, you will be able to read and store dates in your SwiftUI app.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">DateView<\/span>: View {\n    @AppStorage(<span style=\"color:#e6db74\">&#34;savedDate&#34;<\/span>) <span style=\"color:#66d9ef\">var<\/span> date: Date = Date()\n    \n    <span style=\"color:#66d9ef\">var<\/span> body: some View {\n        VStack {\n            Text(date, style: .date)\n            Text(date, style: .time)\n            Button(<span style=\"color:#e6db74\">&#34;Save date&#34;<\/span>) { date = Date() }\n        }\n    }\n}\n<\/code><\/pre><\/div><img src=\"https:\/\/kamil.id\/uploads\/2024\/appstorage-date-xcode-example-project.png\" width=\"600\" height=\"379\" alt=\"AppStorage Date example in Xcode Project\">\n"},{"title":"How to use EnvironmentObjects with SwiftUI Live Preview","link":"https:\/\/kamil.id\/2021\/01\/20\/how-to-use-environmentobjects-with\/","pubDate":"Wed, 20 Jan 2021 17:17:00 +0100","guid":"http:\/\/kamil.micro.blog\/2021\/01\/20\/how-to-use-environmentobjects-with\/","description":"<img src=\"https:\/\/kamil.id\/uploads\/2024\/how-to-use-environmentobjects-with-swiftui-live-preview.png\" width=\"600\" height=\"360\" alt=\"How to use EnvironmentObjects with SwiftUI Live Preview\">\n<p>SwiftUI views in larger applications may use some configuration passed to them as environment objects. It is a very beneficial way when the config is needed somewhere deep into a view tree. If your view uses the <code>@EnvironmentObject<\/code> property wrapper, you can still debug and tweak it using live preview functionality.<\/p>\n<p>Take a look at this example. In the <a href=\"https:\/\/kamil.id\/2021\/01\/18\/how-to-add.html\">article about home screen Quick Actions in SwiftUI<\/a>, I&rsquo;ve used <code>ObservableObject<\/code> called <code>QuickActionService<\/code>. You can use it to pass selected Quick Action to the given view.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">import<\/span> <span style=\"color:#a6e22e\">Foundation<\/span>\n\n<span style=\"color:#66d9ef\">enum<\/span> <span style=\"color:#a6e22e\">QuickAction<\/span>: String {\n    <span style=\"color:#66d9ef\">case<\/span> newMessage, search, inbox\n}\n\n<span style=\"color:#66d9ef\">final<\/span> <span style=\"color:#66d9ef\">class<\/span> <span style=\"color:#a6e22e\">QuickActionService<\/span>: ObservableObject {\n    @Published <span style=\"color:#66d9ef\">var<\/span> action: QuickAction? = <span style=\"color:#66d9ef\">nil<\/span>\n}\n<\/code><\/pre><\/div><p>When you provide that object using <code>environmentObject<\/code> modifier, you can listen to changes in it in any place down the view tree.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">private<\/span> <span style=\"color:#66d9ef\">let<\/span> quickActionService = QuickActionService()\n\n<span style=\"color:#66d9ef\">var<\/span> body: some Scene {\n    WindowGroup {\n        ContentView()\n            .environmentObject(quickActionService)\n    }\n}\n<\/code><\/pre><\/div><p>Live previews, though, are rendered without that context of upper views. So you have to use the same <code>environmentObject<\/code> modifier in your preview code.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView_Previews<\/span>: PreviewProvider {\n    <span style=\"color:#66d9ef\">static<\/span> <span style=\"color:#66d9ef\">var<\/span> previews: some View {\n        ContentView()\n            .environmentObject(QuickActionService())\n    }\n}\n<\/code><\/pre><\/div><p>With a slight modification of <code>QuickActionService<\/code>:<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">final<\/span> <span style=\"color:#66d9ef\">class<\/span> <span style=\"color:#a6e22e\">QuickActionService<\/span>: ObservableObject {\n    @Published <span style=\"color:#66d9ef\">var<\/span> action: QuickAction?\n    \n    <span style=\"color:#66d9ef\">init<\/span>(initialValue: QuickAction? = <span style=\"color:#66d9ef\">nil<\/span>) {\n        action = initialValue\n    }\n}\n<\/code><\/pre><\/div><p>you will be able to test different versions of your screen based on different values for quick action parameters.<\/p>\n<div class=\"highlight\"><pre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4\"><code class=\"language-swift\" data-lang=\"swift\"><span style=\"color:#66d9ef\">struct<\/span> <span style=\"color:#a6e22e\">ContentView_Previews<\/span>: PreviewProvider {\n    <span style=\"color:#66d9ef\">static<\/span> <span style=\"color:#66d9ef\">var<\/span> previews: some View {\n        Group {\n            ContentView()\n                .environmentObject(QuickActionService())\n            ContentView()\n                .environmentObject(QuickActionService(initialValue: .newMessage))\n        }\n    }\n}\n<\/code><\/pre><\/div>"}]}}