Lists: Improving the User Experience Programmatically

Free iOS Development Tutorial

Learn how to refine your iOS app interface with this iOS Development tutorial, featuring a detailed exercise that guides you through steps to improve UI elements such as spacing, cell backgrounds, text styles, and navigation bar color.

This exercise is excerpted from Noble Desktop’s past app development training materials and is compatible with iOS updates through 2021. To learn current skills in web development, check out our coding bootcamps in NYC and live online.

Topics Covered in This IOS Development Tutorial:

Increasing the Spacing Between the Add New List Area & the First List Title, Changing the Background Images When List Table View Cells Are Selected, Displaying a Completed List Item’s Text in Bold, Darkening the Header in the Navigation Controller

Exercise Preview

ex prev lists ux improvement

Exercise Overview

Now that our app has persistent storage, it’s finally useful from a user perspective. However, there are a few improvements we can make to the UI to make the app more elegant and easier to use. We’ll do so in this exercise using code. We are going to improve spacing, make the cell backgrounds on both screens change color when the user selects them, add code that bolds the text for checked list items, and make the navigation bar at the top a darker yellow.

Full-Stack Web Development Certificate: Live & Hands-on, In NYC or Online, 0% Financing, 1-on-1 Mentoring, Free Retake, Job Prep. Named a Top Bootcamp by Forbes, Fortune, & Time Out. Noble Desktop. Learn More.

Getting Started

  1. Launch Xcode if it isn’t already open.

  2. If you completed the previous exercise, Lists.xcodeproj should still be open. If you closed it, re-open it now.

  3. We suggest you complete the previous exercises (5A–6C) before doing this one. If you did not do the previous exercises, complete the following:

    • Go to File > Open.
    • Navigate to Desktop > Class Files > yourname-iOS App Dev 2 Class > Lists Ready for UX Improvement and double–click on Lists.xcodeproj.

Increasing the Spacing Between the Add New List Area & the First List Title

  1. If the Simulator isn’t still running, go to Xcode and Run run icon it now.

  2. Make sure you are on the first screen with the list titles.

  3. Look at the Add new list area below the navigation bar (with the text field and Plus (+) button), then look at the first list title below it.

    The spacing between them looks oppressively cramped. We think it would look better if we add a bit of spacing on top of the first list title, as shown on the right side of the image below:

    lists top inset comparison

  4. In Xcode, click on the ListsVC.swift tab (or open a new tab and navigate there now if you closed it).

  5. Near the top of the code, find the viewDidLoad method.

    This method gets called once, when the view initially loads. In the previous exercise we added the loadLists() method call that loads all the list titles that were previously saved. It only needs to be called a single time, but the code we want to add may need to be called more than once. This is because the user may add multiple lists, and the topmost list may change thanks to our alphabetical sorting.

    This means we’ll need to override another one of Apple’s pre-coded methods for the UIViewController class. Let’s use one that can get called multiple times.

  6. Between viewDidLoad and the MARK comment, add the viewWillAppear method that prepares the view to appear on-screen anytime it visually changes. (Accept Xcode’s suggestion when it’s available, so you get the code shown below.)

    override func viewDidLoad() {
          super.viewDidLoad()
          loadLists()
       }
    
       override func viewWillAppear(_ animated: Bool) {
          code
       }
    
    
    // MARK:—TableView DataSource methods————————————
  7. To push the top of the table view down without changing any of the other positioning values, add the following line of code:

    override func viewWillAppear(_ animated: Bool) {
       listsTableView.contentInset = UIEdgeInsets(top: listsTableView.frame.height/38, left: 0, bottom: 0, right: 0)
    }
  8. Let’s break that down:

    • By default, there is no inset (extra space) between a table view and its parent container. The contentInset property allows us to change that.
    • UIEdgeInsets specify a distance in points. We’re using the default value of 0 everywhere we don’t want any insets. Positive values add more space, shrinking the frame. Negative values expand the frame.
    • We’re pushing the frame downward by 1/38 of the Table View’s total height. This dynamically calculated value looks good on any size iPhone—we found it using trial and error.
  9. Run run icon the Simulator to see the difference. Our list titles have more breathing room!

  10. Click on one of the stored list names to highlight it. Then at the top left of the next screen, click the < Lists button to return to the first screen.

    By default, the background of a selected cell is light gray. We aren’t using gray elsewhere, so it looks rather unsightly in our app. It would look better with no background color. Because we don’t want the color, we’ll need a way to indicate to the user who the cell is selected. Let’s change its background image!

Changing the Background Images When List Table View Cells Are Selected

To swap out the two possible backgrounds behind the list title, we’ll need to go into the code for the cell and specify a different behavior if the Table View Cell object is selected. We can do that in the setSelected function that Apple helpfully added automatically when we created the file in a previous exercise.

  1. Let’s open the file in a new tab. Press Cmd–T, then in the Project navigator click on ListTitleTVCell.swift.

  2. In the setSelected function, we want to test whether the selected property in the parentheses is true or false. Add the bold if-else statement:

    override func setSelected(_ selected: Bool, animated: Bool) {
       super.setSelected(selected, animated: animated)
       if selected {
    
       }
       else {
    
       }
    }

    This function is called every time a cell on the parent Table View (ListsTableView) is loaded or changed.

  3. We want to set the background image based on whether the cell is selected or not. Assign the different images by passing in their file names as arguments:

    if selected {
       backgroundImageView.image = UIImage(named: "CellSelectedBackground")
    }
    else { backgroundImageView.image = UIImage(named: "CellDeselectedBackground") }
  4. Let’s get rid of that gray highlight. We can’t actually remove it, but we can change it to the exact color we used for the cell background using RGBA values (RGB plus alpha transparency). Switch to the Main.storyboard tab or open it in a new tab.

  5. On the first View Controller (the middle one in our 3-controller setup), click slightly to the left or right of the gradated yellow background behind the List Name label. If the Document Outline is open, the ListTitleTVCell should be selected.

  6. We can check the color, make sure the Attributes inspector attributes inspector icon is selected.

  7. In the Attributes inspector next to Background, click on the bar.

  8. In the pop-up that appears, take note of the RGB values as well as the Opacity. You should have Red: 250, Green: 247, and Blue: 235. Opacity should be 100%.

  9. Let’s use these values in our code! Dismiss the Color pop-up and switch back to the ListTitleTVCell.swift tab.

  10. Change the background color for the contentView that contains the cell’s visuals by adding the bold line of code:

    if selected {
       backgroundImageView.image = UIImage(named: "CellSelectedBackground")
       contentView.backgroundColor = UIColor(displayP3Red: 250/255, green: 247/255, blue: 235/255, alpha: 1)
    }
  11. Let’s test it out! Run run icon the Simulator once more.

  12. Highlight the cell and you’ll see that the image changes and it now blends in well with our overall design! (You may have to go back a screen to get a better look.)

  13. If you aren’t on the second screen that displays list items, click on a list name to navigate there.

  14. Do the following to see these two areas for improvement:

    • Click on the title of one of the list items to select it. There’s that pesky gray again! Let’s change this background color to a nice peppy yellow.
    • Check an unchecked item. It’s nice that the Check button’s image changes, but the image change might be too subtle for users who are in a hurry or otherwise distracted to gauge which items have been completed. Let’s make the text bold.

Displaying a Completed List Item’s Text in Bold

  1. In Xcode, click on the ListItemTVCell.swift tab (or open a new tab and navigate there now if you closed it).

  2. To change the background color for selected cells from light gray to light yellow, fill in the provided setSelected method as follows:

    override func setSelected(_ selected: Bool, animated: Bool) {
       super.setSelected(selected, animated: animated)
       if selected { contentView.backgroundColor = UIColor(displayP3Red: 252/255, green: 238/255, blue: 183/255, alpha: 1) }
    }

    NOTE: We haven’t used this exact color elsewhere in our interface, but it matches our color scheme. The RGBA values (and hex code we aren’t using) were provided to us by the designer, as is expected. If your designer forgets to give you these values, just ask for them.

  3. In the checkButtonTapped custom method that gets executed whenever the user taps this button, change the font weight based on whether or not the item is checked off by adding the following ternary conditional operator (as a single long line of code):

    checkButton.setImage(item.checked ? UIImage(named: "Checked") : UIImage(named: "Unchecked"), for:.normal)
    itemNameLabel.font = item.checked ? UIFont.systemFont(ofSize: 17, weight: UIFontWeightBold) : UIFont.systemFont(ofSize: 17, weight: UIFontWeightRegular)
    saveLists()

    Just like the ternary conditional operator we added in a previous exercise, we’re checking whether the item is checked (using the ? operator). If so, we’re setting its font weight to bold. Otherwise (:) it will be regular weight.

    NOTE: We also needed to specify that it will remain the 17 px default system font (San Francisco) that we’ve been using. Otherwise, the font will look the same as before.

  4. If you remember from the previous exercise, a Table View Cell cannot hold on to its checked/unchecked state! Remember that this is because Table View Cells (but not their content) get recycled. This means we need to add this code in the parent Table View. Select the entire itemNameLabel.font line shown below and copy it.

    itemNameLabel.font = item.checked ? UIFont.systemFont(ofSize: 17, weight: UIFont. Weight.bold) : UIFont.systemFont(ofSize: 17, weight: UIFont. Weight.regular)
  5. Click on the ListItemsVC.swift tab (or open a new tab and navigate there now if you closed it).

  6. In the TableView DataSource methods section’s cellForRowAt method, paste the code as shown in bold:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    Code Omitted To Save Space

    listItemTVCell.itemNameLabel.text = listItemTVCell.item.title
       itemNameLabel.font = item.checked ? UIFont.systemFont(ofSize: 17, weight: UIFont. Weight.bold) : UIFont.systemFont(ofSize: 17, weight: UIFont. Weight.regular)
       listItemTVCell.checkButton.setImage(listItemTVCell.item.checked ? UIImage(named: "Checked") : UIImage(named: "Unchecked"), for:.normal)
    
       return listItemTVCell
    }
  7. The itemNameLabel and checked properties were declared in the listItemTVCell. To make the red error go away, add the bold code:

    listItemTVCell. itemNameLabel.font = listItemTVCell. item.checked ? UIFont.systemFont(ofSize: 17, weight: UIFont. Weight.bold) : UIFont.systemFont(ofSize: 17, weight: UIFont. Weight.regular)
  8. Run run icon the Simulator again. When it loads, click on a list name to see the items inside it.

  9. Select any list item by clicking anywhere except the Check button. Great, there’s our yellow highlight!

  10. Click any item’s Check button on and off to see the font weight change. It will be bold when it is checked, and regular size when it isn’t.

    Feel free to do this with multiple items to see that the font weight always changes like we told it to do. This is because we’re not relying solely on the Table View Cell to maintain the state of the font weight inside it.

Darkening the Header in the Navigation Controller

Now that our two screens look nice and punchy, the pale yellow header (the status and navigation bar area) looks a little weak. We can change its background color to a darker yellow, but we cannot do so on the Storyboard. Let’s create a file with a new class so we can change the color programmatically.

  1. Go back to Xcode if you aren’t already there.

  2. To ensure the new file gets organized in the proper place, go to the Project navigator project navigator icon and click on the Lists folder (not the name of the project).

  3. Go to File > New > File or use the shortcut Cmd–N.

  4. Under iOS and Source, double–click on the Cocoa Touch Class template.

  5. Create a subclass of the UINavigationController that is managing the navigation for our app:

    Subclass of: UINavigationController (Remember to set this first!)
    Class: NavigationController
  6. Click Next, then in the next screen click Create.

  7. The new file should appear automatically in the Editor. Delete everything except the following code:

    import UIKit
    
    class NavigationController: UINavigationController {
    
       override func viewDidLoad() {
          super.viewDidLoad()
       }
    
    }
  8. Let’s customize our navigation controller by adding a background image with the color we want. This only needs to happen once—when the view initially loads. So add the bold line of code inside the viewDidLoad method:

    override func viewDidLoad() {
       super.viewDidLoad()
    
       navigationBar.setBackgroundImage(UIImage(named: "NavigationBarBackground"), for: UIBarMetrics.default)
    }

    NOTE: Our custom background image is a tiny 9 X 9 pixel image that will get tiled both horizontally and vertically to fill the space. If you want to take a look, feel free to open the image (from the Images folder) in a new tab.

  9. We just added a custom background image to the navigation bar. This changes how Swift decides whether or not to make the bar semi-transparent. If any of the pixels are semi-transparent, the header will also be semi-transparent. Now that we have a better color, we want this effect. However, our custom image is 100% opaque. To get some translucency, add the following line:

    super.viewDidLoad()
    navigationBar.isTranslucent = true
    navigationBar.setBackgroundImage(UIImage(named: "NavigationBarBackground"), for: UIBarMetrics.default)

    This changed the default value of false (for an opaque image with an alpha value of 1.0) to true, so we will get the semi-transparency we want.

  10. Run run icon the Simulator.

    The navigation bar looks… the same as before?! Oops, we forgot to tell the Navigation Controller that it’s associated with the file we just created! It’s easy to overlook this step but luckily the fix is equally easy.

  11. Back in Xcode, click on the Main.storyboard tab (or open a new tab and navigate there now if you closed it).

  12. Go to the top right and switch to the Identity inspector identity inspector icon tab.

  13. Remember that because it’s the initial controller, the Navigation Controller is the leftmost of our three controllers. If you can’t see it, scroll there now.

  14. In the Editor, click in the center of the Navigation Controller (anywhere in the gray area).

  15. At the top of the Identity inspector identity inspector icon next to Class, start typing NavigationController. Once it gives you the correct suggestion, press Return.

  16. Run run icon the Simulator again.

    Now that Xcode knows which file contains the relevant code, our header now has the color we want!

  17. Click on a list title to advance to the next screen. Great, the header looks nice here too. Remember that because the Navigation Controller controls the entire flow of navigation (the two View Controllers that actually display visuals), the header for all the screens will be the custom color.

    Our app looks and functions exactly how we want, so we are finally done. Congratulations, you can check this app off of your to-do list!

  18. Return to Xcode and Stop stop icon the Simulator.

  19. Save and close the project but leave Xcode open for the next exercise.

Noble Desktop Publishing Team

The Noble Desktop Publishing Team includes writers, editors, instructors, and industry experts who collaborate to publish up-to-date content on today's top skills and software. From career guides to software tutorials to introductory video courses, Noble aims to produce relevant learning resources for people interested in coding, design, data, marketing, and other in-demand professions.

More articles by Noble Desktop Publishing Team

How to Learn IOS & Web Development

Master IOS Development, Web Development, Coding, and More with Hands-on Training. IOS Development Involves Designing Apps for Apple Mobile Devices with Tools Like Xcode and SwiftUI.

Yelp Facebook LinkedIn YouTube Twitter Instagram