LAST CHANCE: Save 50% on all my Swift books and bundles! >>

UI questions with SwiftUI

Forums > SwiftUI

Hi,

I'm still rather new to SwiftUI (my prior experience is with SuperCard for making macOS apps). After finishing up "100 Days Of SwiftUI" (for iOS), and while waiting for Paul to release an updated iBook for SwiftUI for macOS, I decided to explore iOS development for a bit with a fun project in the latest version of Xcode/Swift. I've run into a couple of UI questions on iOS that I'm hoping someone with more experience can answer or offer advice on.

  1. I have a form. In the first line I put in a DatePicker. I set it up to only include the date component. When I tap on the date which appears as "Apr 6, 2021" with a grey rounded rectangle background, the screen blurs and I get a nice date picker appearing centered on the screen. I can select a date and... nothing happens. By this, I mean, the date picker doesn't go away when I tap on a date... it just stays there unless I tap outside of it in the blurred background. Is this expected behavior or is there something I'm missing? Also, sometimes when I've changed the date and I tap outside to close the date picker, the text of the date picker suddenly changes to use 4/6/2021, except... it does this starting at the same left edge as things were with the prior "Apr 6, 2021" and shrinks the grey round rectangle inward on the right side - which leaves a larger white space on the right side of the list (that seems rather odd). I have not yet tried this on my iPod touch or iPad Pro (just the simulator). Is this some sort of known bug either with the date picker or in the simulator? Also, is there a way to customize how the date appears in the date picker (I only see options for date, time or both but nothing about the format for the date itself). I was thinking maybe if I could just change it to using 4/6/2021 it could get around this weirdness.

  2. Moving on to the next line of my form... I put in a Picker. What I would like to do is offer users some default choices in this picker and then at the bottom have a "Custom..." item which will take the user to another view to create a custom option. In macOS (with SuperCard) I'd use a popup menu and I would even use dividers to seperate logical groupings in my predefined choices. So... here I'm talking about date ranges... 30 Day, 60 Day, 90 Day (dividing line) 3 Month, 6 Month, 9 Month (dividing line) 1 Year, 2 Year, 3 Year (dividing line) Custom...

I know I can do an array of strings (without dividing lines) as Paul covered that in "100 Days Of SwiftUI", but I'm not really seeing any way of creating the logical groupings in a picker. Also, what I would want to do is display the Custom made item as the name of the picker control in my form... so for example if the user enters "45 Day", or "5 Year" that would appear as the name. And then when selecting the picker have it show the checkmark next to "Custom..." since that isn't one of the predefined options. I experimented with trying to change the name to something not in the Array, but this just results in an empty control (just showing the navigation link icon on the right).

Is there a way in SwiftUI to do what I am trying to do? Would I be better off creating a HStack and putting in a Text (for my label on the left), a spacer, and a textField (for the value), and a picker (for just an array of "Day", "Week", "Month", "Year") - essentially making EVERY entry a "Custom" entry. And actually, that brings me to another question... is it possible to hide the label that would appear to the left on the picker control (or any of the other controls for that matter)?

It would be a bit sad if I couldn't offer some presets of most common values here to make it easier for the user, but if that is really the only good option, well, I could live with something like that.

   

On the second question above, it appears that Apple is providing me with some guidance here in the way it should be done (based on their Calendar app). It is always good to find an example from Apple. Unfortunately I'm not sure if it can be done in SwiftUI.

  1. Go to Calendar
  2. Create a new event
  3. Scroll to the Repeat option
  4. Tap on Never. It brings up the predefined choices grouped together (Never, Every Day, Every Week... Every Year) and it also includes another section with Custom that leads off to the side.
  5. Tap Custom... In here they break apart the two items for Frequency and Every and use scroll wheel pickers for selecting the choices. They also summarize what options are selected below the section such as "Event will occur every 45 days".
  6. Backing out of that to the Repeat menu, it puts a checkmark next to custom (the navigation link icon no longer appears here - though you can still tap that line to edit it). And below the section with Custom it now includes the same summary (so at least you don't have to go into Custom itself to see what options were selected.
  7. Backing out to the new event, the Repeat option is simply custom.

Any tips on how to do something like this in SwiftUI or is this level of customization beyond the capabilities of SwiftUI and falls into the realm of UIKit?

   

Or... do I have to fake all of this using other SwiftUI elements? I mean, I think I could use a navigation link to my own view, I could set up a list with a grouped list style and put my options into sections. I could use buttons or tap gesture to make my selection and return to the previous view. I could use a HStack and spacer and a SFSymbol "checkmark" and show that only next to the item that matches which item was selected when my view opens. I'm not really sure about the Custom option though (as it works in Calendar). It would be easy to include a navigation link there to yet another custom view (and I think hiding or showing wheel pickers there would be the same sort of thing as hiding or showing a section based on a toggle button - which Paul covers in "100 Days Of SwiftUI"... but I'm not sure how one would hide the ">" at the end of my "Custom" row and only show a checkmark if that was the choice that had been made.

Is that the way to tackle this or is there some other (easier) option? I'd hate to go through doing all that and have someone say, why didn't you just do it this other way?

   

I haven't replied before now because my answer is, "I don't know." But because nobody else has piped up, I suspect nobody else here knows, either. It is very easy for me to believe that the canonical answer is, "That's not available, out of the box."

From tutorials (Paul's, here, as well as other folks' on YouTube and elsewhere) I've seen, the SwiftUI Way To Do It is with composition, layering many Views together to achieve whatever effect.

   

Thanks @sbeitzel. Yeah, I'm sort of torn over this one. Ideally I was hoping there might be some obvious answer here (at least obvious to everyone except me)... like the way you can have Xcode generate the files in Core Data so you can customize things (except in a case like this have it provide whatever code it is auto-generating for the view that it goes to from the picker in the form so you can modify it) or perhaps some syntax where you could create a view to inject into the process but as long as it conforms to certain protocols or something it would work with the picker control. I've been searching around while waiting for a reply here, but only seem to be finding cases where people want to generate something that is completely unique as a picker, not actually customize the view the picker generates itself when used in a form.

Fortunately this is a fun project I'm doing in the gap between finishing "100 Days Of SwiftUI" (for iOS) and waiting for Paul to update his macOS book to using SwiftUI, so I'm not really under any pressure of time contstraints or deadlines... but that said, I don't want to just be sitting around perpetually waiting either, so maybe I'll just give it a little more time and if no other replies come in, I'll just start working on my own approximation of that picker from the pieces we have in SwiftUI.

   

I'm having some luck faking the picker UI that I described in Calendar events when selecting the Repeat line. I created a new view, set up an @State private var to keep track of the selection, set up a NavigationView, set up a list. Set the list to be GroupedListStyle() which gives me the proper appearance. Set up a first section in a ForEach with HStack, a Button, a Spacer() and an image with systemName "checkmark" and a condition to only show it if the selection matches the name... so I can loop through my array of pre-defined choices (awesome).

I'm having a problem with faking the picker UI for the second section in my list because the behavior is a bit odd (from Apple). I need to navigate to a new view to set up my custom interval... so I tried putting in a NavigationLink and that does give me the initial appearance for the item with "Custom" on the left and the chevron on the right (and I can use the section footer below that to show what custom options were selected - just like the Apple Calendar UI). BUT... If you follow this through in the Calendar app as an example, when you make your Custom selection and return to the previous view, the chevron is replaced with a checkmark. I can't figure out a way to do this. If I include the NavigationLink in a HStack, I can add a checkmark, but that just pushes the chevron in to the left and puts my checkmark to the right of that... not replacing it. I could fake the chevron using the systemName "chevron.right" if there is a way to just hide the genuine chevron from the NavigationLink and swap the two depending on if Custom is the selection or not. Is there a way to do this or should I just give up here and call it a win with the indented genuine chevron and the checkmark to the right of it? (I could probably even make a case here that this UI is better than Apple's because the included chevron shows that you can tap on the selected Custom item to change the options where Apple's UI doesn't have any visual indication of that).

   

Click here to save 50% on all my books and bundles!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.