
{"id":1234,"date":"2024-07-10T17:00:14","date_gmt":"2024-07-10T16:00:14","guid":{"rendered":"https:\/\/hennig.nu\/?p=1234"},"modified":"2024-07-15T16:49:34","modified_gmt":"2024-07-15T15:49:34","slug":"reusable-gradient-view","status":"publish","type":"post","link":"https:\/\/hennig.nu\/coding\/reusable-gradient-view","title":{"rendered":"Reusable gradient view"},"content":{"rendered":"\n<p>The first code snippet I&#8217;d like to share comes from a simple game I created for my daughter. The origin is a challenge from <a href=\"https:\/\/www.hackingwithswift.com\/100\/swiftui\" data-type=\"link\" data-id=\"https:\/\/www.hackingwithswift.com\/100\/swiftui\">100 days of SwiftUI<\/a>, where you are supposed to create an app for training the times tables. Back then I only got the logic working, but when she started with multiplications in school this year, she asked if could finish it for her. <\/p>\n\n\n\n<p>At first I planned to get it on her phone with Test Flight, but it turns out that you have to be sixteen to install Test Flight. So I realised the only viable option was to go through App Store, and since that meant the app would be available to anyone with an iPhone I&#8217;d better put some effort in the interface. <\/p>\n\n\n\n<p>With some input from my target audience I ended up with a gradient based theme, and now we&#8217;ve arrived to the reason for this post, the progress tracking view. <\/p>\n\n\n\n<p>It&#8217;s a pretty simple table layout (or a LazyVgrid to be accurate) that shows how many times you&#8217;ve played \u2013 or practiced \u2013 each table, that is represented by different gradients, looking a bit like candy. Maybe that&#8217;s why my daughter likes them\u2026<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1341\" height=\"2664\" data-attachment-id=\"1235\" data-permalink=\"https:\/\/hennig.nu\/coding\/reusable-gradient-view\/attachment\/rocketsim_screenshot_iphone_15_pro_6-1_2024-07-10_17-19-29\" data-orig-file=\"https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29.png\" data-orig-size=\"1341,2664\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29.png\" src=\"https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29.png\" alt=\"\" class=\"wp-image-1235\" style=\"width:366px;height:auto\" srcset=\"https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29.png 1341w, https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29-235x466.png 235w, https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29-768x1526.png 768w, https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29-773x1536.png 773w, https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29-1031x2048.png 1031w, https:\/\/hennig.nu\/wp-content\/uploads\/2024\/07\/RocketSim_Screenshot_iPhone_15_Pro_6.1_2024-07-10_17.19.29-1200x2384.png 1200w\" sizes=\"auto, (max-width: 1341px) 100vw, 1341px\" \/><\/figure>\n\n\n\n<p>The code is pretty straightforward. Each table is created by calling a GradientView that takes a few arguments. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:4;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"struct GradientView: View {\n\tlet gradient: Gradient\n\tlet width: CGFloat\n\tlet height: CGFloat\n\tlet radius: CGFloat\n\tlet tabell: LocalizedStringResource\n\tlet spel: Int\n\n    var body: some View {\n\t\tLinearGradient(gradient: gradient, startPoint: .topLeading, endPoint: .bottomTrailing)\n\t\t\t.clipShape(RoundedRectangle(cornerRadius: radius))\n\t\t\t.frame(width: width, height: height, alignment: .center)\n\t\t\t.overlay {\n\t\t\t\tRoundedRectangle(cornerRadius: 5)\n\t\t\t\t\t.strokeBorder(.ultraThinMaterial, lineWidth: 0.35)\n\t\t\t\tVStack {\n\t\t\t\t\tText(tabell)\n\t\t\t\t\t\t.font(Font.custom(Fonts.primary, size: 22))\n\t\t\t\t\tText(&quot;\\(spel)&quot;)\n\t\t\t\t\t\t.font(Font.custom(Fonts.primary, size: 28))\n\t\t\t\t}\n\t\t\t\t.shadow(color: .black, radius: 1)\n\t\t\t}\n\t\t\t.shadow(radius: 1, x: 1, y: 2)\n\t\t\t.foregroundStyle(.white)\n    }\n}\" style=\"color:#F8F8F2;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #FF79C6\">struct<\/span><span style=\"color: #F8F8F2\"> <\/span><span style=\"color: #8BE9FD; font-style: italic\">GradientView<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #8BE9FD; font-style: italic\">View <\/span><span style=\"color: #F8F8F2\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> gradient: Gradient<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> width: CGFloat<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> height: CGFloat<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> radius: CGFloat<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> tabell: LocalizedStringResource<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> spel: <\/span><span style=\"color: #8BE9FD; font-style: italic\">Int<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">    <\/span><span style=\"color: #FF79C6\">var<\/span><span style=\"color: #F8F8F2\"> body: <\/span><span style=\"color: #FF79C6\">some<\/span><span style=\"color: #F8F8F2\"> View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t<\/span><span style=\"color: #8BE9FD\">LinearGradient<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">gradient<\/span><span style=\"color: #F8F8F2\">: gradient, <\/span><span style=\"color: #8BE9FD\">startPoint<\/span><span style=\"color: #F8F8F2\">: .topLeading, <\/span><span style=\"color: #8BE9FD\">endPoint<\/span><span style=\"color: #F8F8F2\">: .bottomTrailing)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t.<\/span><span style=\"color: #8BE9FD\">clipShape<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">RoundedRectangle<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">cornerRadius<\/span><span style=\"color: #F8F8F2\">: radius))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t.<\/span><span style=\"color: #8BE9FD\">frame<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">width<\/span><span style=\"color: #F8F8F2\">: width, <\/span><span style=\"color: #8BE9FD\">height<\/span><span style=\"color: #F8F8F2\">: height, <\/span><span style=\"color: #8BE9FD\">alignment<\/span><span style=\"color: #F8F8F2\">: .center)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t.<\/span><span style=\"color: #8BE9FD\">overlay<\/span><span style=\"color: #F8F8F2\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t<\/span><span style=\"color: #8BE9FD\">RoundedRectangle<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">cornerRadius<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">5<\/span><span style=\"color: #F8F8F2\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t\t.<\/span><span style=\"color: #8BE9FD\">strokeBorder<\/span><span style=\"color: #F8F8F2\">(.ultraThinMaterial, <\/span><span style=\"color: #8BE9FD\">lineWidth<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">0.35<\/span><span style=\"color: #F8F8F2\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t<\/span><span style=\"color: #8BE9FD\">VStack<\/span><span style=\"color: #F8F8F2\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t\t<\/span><span style=\"color: #8BE9FD\">Text<\/span><span style=\"color: #F8F8F2\">(tabell)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t\t\t.<\/span><span style=\"color: #8BE9FD\">font<\/span><span style=\"color: #F8F8F2\">(Font.<\/span><span style=\"color: #8BE9FD\">custom<\/span><span style=\"color: #F8F8F2\">(Fonts.primary, <\/span><span style=\"color: #8BE9FD\">size<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">22<\/span><span style=\"color: #F8F8F2\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t\t<\/span><span style=\"color: #8BE9FD\">Text<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #E9F284\">&quot;<\/span><span style=\"color: #FF79C6\">\\(<\/span><span style=\"color: #F1FA8C\">spel<\/span><span style=\"color: #FF79C6\">)<\/span><span style=\"color: #E9F284\">&quot;<\/span><span style=\"color: #F8F8F2\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t\t\t.<\/span><span style=\"color: #8BE9FD\">font<\/span><span style=\"color: #F8F8F2\">(Font.<\/span><span style=\"color: #8BE9FD\">custom<\/span><span style=\"color: #F8F8F2\">(Fonts.primary, <\/span><span style=\"color: #8BE9FD\">size<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">28<\/span><span style=\"color: #F8F8F2\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t\t.<\/span><span style=\"color: #8BE9FD\">shadow<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">color<\/span><span style=\"color: #F8F8F2\">: .black, <\/span><span style=\"color: #8BE9FD\">radius<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">1<\/span><span style=\"color: #F8F8F2\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t.<\/span><span style=\"color: #8BE9FD\">shadow<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">radius<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">1<\/span><span style=\"color: #F8F8F2\">, <\/span><span style=\"color: #8BE9FD\">x<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">1<\/span><span style=\"color: #F8F8F2\">, <\/span><span style=\"color: #8BE9FD\">y<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">2<\/span><span style=\"color: #F8F8F2\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t.<\/span><span style=\"color: #8BE9FD\">foregroundStyle<\/span><span style=\"color: #F8F8F2\">(.white)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The only important properties to create the View are gradient, width, height and radius. The last two are used to pass in the text that is displayed and can be replaced with whatever fits your needs.<\/p>\n\n\n\n<p>Then I simply call the view in a ForEach, inside my LazyVGrid.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:4;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"LazyVGrid(columns: gridItems, spacing: width \/ 32) {\n    ForEach(gameController.player.timesEachTablePlayed.indices.dropFirst(), id: \\.self) { i in\n\t\tGradientView(\n\t\t\tgradient: Gradients.gradients[i],\n\t\t\twidth: height \/ 8,\n\t\t\theight: height \/ 8,\n\t\t\tradius: 8,\n\t\t\ttabell: globals.tabellerna[i],\n\t\t\tspel: gameController.player.timesEachTablePlayed[i]\n\t\t)\n\t}\n}\" style=\"color:#F8F8F2;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #8BE9FD\">LazyVGrid<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">columns<\/span><span style=\"color: #F8F8F2\">: gridItems, <\/span><span style=\"color: #8BE9FD\">spacing<\/span><span style=\"color: #F8F8F2\">: width <\/span><span style=\"color: #FF79C6\">\/<\/span><span style=\"color: #F8F8F2\"> <\/span><span style=\"color: #BD93F9\">32<\/span><span style=\"color: #F8F8F2\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">    <\/span><span style=\"color: #8BE9FD\">ForEach<\/span><span style=\"color: #F8F8F2\">(gameController.player.timesEachTablePlayed.<\/span><span style=\"color: #BD93F9\">indices<\/span><span style=\"color: #F8F8F2\">.<\/span><span style=\"color: #8BE9FD\">dropFirst<\/span><span style=\"color: #F8F8F2\">(), <\/span><span style=\"color: #8BE9FD\">id<\/span><span style=\"color: #F8F8F2\">: \\.<\/span><span style=\"color: #FF79C6\">self<\/span><span style=\"color: #F8F8F2\">) { i <\/span><span style=\"color: #FF79C6\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t<\/span><span style=\"color: #8BE9FD\">GradientView<\/span><span style=\"color: #F8F8F2\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t<\/span><span style=\"color: #8BE9FD\">gradient<\/span><span style=\"color: #F8F8F2\">: Gradients.gradients[i],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t<\/span><span style=\"color: #8BE9FD\">width<\/span><span style=\"color: #F8F8F2\">: height <\/span><span style=\"color: #FF79C6\">\/<\/span><span style=\"color: #F8F8F2\"> <\/span><span style=\"color: #BD93F9\">8<\/span><span style=\"color: #F8F8F2\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t<\/span><span style=\"color: #8BE9FD\">height<\/span><span style=\"color: #F8F8F2\">: height <\/span><span style=\"color: #FF79C6\">\/<\/span><span style=\"color: #F8F8F2\"> <\/span><span style=\"color: #BD93F9\">8<\/span><span style=\"color: #F8F8F2\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t<\/span><span style=\"color: #8BE9FD\">radius<\/span><span style=\"color: #F8F8F2\">: <\/span><span style=\"color: #BD93F9\">8<\/span><span style=\"color: #F8F8F2\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t<\/span><span style=\"color: #8BE9FD\">tabell<\/span><span style=\"color: #F8F8F2\">: globals.tabellerna[i],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t\t<\/span><span style=\"color: #8BE9FD\">spel<\/span><span style=\"color: #F8F8F2\">: gameController.player.timesEachTablePlayed[i]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>There are a few things worth mentioning. First, I&#8217;ve created an array with predefined gradients to match the twelve playable times tables.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"struct Gradients {\n\tstatic let gradients: [Gradient] = [\n\t\tGradient(colors: [Color(.blue), Color(.yellow), Color(.red)]), \n\t\tGradient(colors: [Color(.white), Color(.red), Color(.pink)]),\n\t\tGradient(colors: [Color(.white), Color(.pink), Color(.orange)]),\n    ... and so on ...\n\t]\n}\n\" style=\"color:#F8F8F2;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dracula\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #FF79C6\">struct<\/span><span style=\"color: #F8F8F2\"> <\/span><span style=\"color: #8BE9FD; font-style: italic\">Gradients<\/span><span style=\"color: #F8F8F2\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t<\/span><span style=\"color: #FF79C6\">static<\/span><span style=\"color: #F8F8F2\"> <\/span><span style=\"color: #FF79C6\">let<\/span><span style=\"color: #F8F8F2\"> gradients: [Gradient] <\/span><span style=\"color: #FF79C6\">=<\/span><span style=\"color: #F8F8F2\"> [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t<\/span><span style=\"color: #8BE9FD\">Gradient<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">colors<\/span><span style=\"color: #F8F8F2\">: [<\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.blue), <\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.yellow), <\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.red)]), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t<\/span><span style=\"color: #8BE9FD\">Gradient<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">colors<\/span><span style=\"color: #F8F8F2\">: [<\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.white), <\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.red), <\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.pink)]),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t\t<\/span><span style=\"color: #8BE9FD\">Gradient<\/span><span style=\"color: #F8F8F2\">(<\/span><span style=\"color: #8BE9FD\">colors<\/span><span style=\"color: #F8F8F2\">: [<\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.white), <\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.pink), <\/span><span style=\"color: #8BE9FD\">Color<\/span><span style=\"color: #F8F8F2\">(.orange)]),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">    <\/span><span style=\"color: #FF79C6\">...<\/span><span style=\"color: #F8F8F2\"> and so on <\/span><span style=\"color: #FF79C6\">...<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">\t]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F8F8F2\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Second, the main view is wrapped in a Geometry Reader to make the layout automatically adjust to the current screen size, hence <code>height\/8<\/code>, being passed to the GradientView. Since I want my buttons to be squares, I don&#8217;t bother using height and instead pass width for both properties.<\/p>\n\n\n\n<p>I admit that this solution has a serious problem. If you can&#8217;t be sure that your ForEach will return the same number of indices on each run, using a fixed set of pre defined gradients is probably not good idea, unless you want your app to crash. But an easy fix could be to use the modulo operator and have the gradients repeat when you run out of them.<\/p>\n\n\n\n<p>I admit that you could probably find a smarter solution, but if want to become a contributor to the swift community, I&#8217;ll have to start somewhere. <\/p>\n\n\n\n<p>This is somewhere.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The first code snippet I&#8217;d like to share comes from a simple game I created for my daughter. The origin is a challenge from 100 days of SwiftUI, where you are supposed to create an app for training the times tables. Back then I only got the logic working, but when she started with multiplications [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[849,850],"tags":[848],"class_list":["post-1234","post","type-post","status-publish","format-standard","hentry","category-coding","category-swift","tag-swift"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pflyg-jU","_links":{"self":[{"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/posts\/1234","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/comments?post=1234"}],"version-history":[{"count":3,"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/posts\/1234\/revisions"}],"predecessor-version":[{"id":1250,"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/posts\/1234\/revisions\/1250"}],"wp:attachment":[{"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/media?parent=1234"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/categories?post=1234"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hennig.nu\/wp-json\/wp\/v2\/tags?post=1234"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}