A Guide to UIView’s Built-in Layout Guides

Since iOS 9 there has been a newcomer in the world of Auto Layout: UILayoutGuide. I knew they exist, but didn’t know they were anything useful. When I wrote programmatic UIKit, I just used the supposedly standard 8 point margin. This is acceptable when there were no notches and safe areas.

aView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8).isActive = true
aView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8).isActive = true
aView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8).isActive = true

Then later I found from auto-complete that these “system spacing” equivalents exist. Along with the NSLayoutConstraint.activate([...]) syntax. Without doing any research, the multiplier sounds like it might work better with dynamic type and accessibility, but I didn’t like it because it only supports iOS 11 or later, and I have an app that I still want to support iOS 10. Also notice the first and second items are swapped for the trailing and bottom constraints. Without swapping it or having a negative multiplier feels like it should work, but no luck so far.

        NSLayoutConstraint.activate([
            aView.topAnchor.constraint(equalToSystemSpacingBelow: view.topAnchor, multiplier: 1),
            aView.leadingAnchor.constraint(equalToSystemSpacingAfter: view.leadingAnchor, multiplier: 1),
            view.trailingAnchor.constraint(equalToSystemSpacingAfter: aView.trailingAnchor, multiplier: 1),
            view.bottomAnchor.constraint(equalToSystemSpacingBelow: aView.bottomAnchor, multiplier: 1),
        ])

Today, I got frustrated with programmatic Auto Layout and wanted to read the official Auto Layout Guide. It’s a shame that I never read it, at least to a degree where I got anything useful from it. When reading it, I came across layoutMarginGuide and readableContentGuide. I didn’t know what was the big deal or what their differences were, so with the added eager to try my freshly downloaded Xcode 13 beta 4, I started a small experiment. As of 2021, here were their differences:

Figure 1 – Different layout guides on an iPad, an iPhone with notch and a 4″ iPod touch

Looking at Figure 1, we have the blue area representing the layout margin guide, green is the readable content guide, and orange being the safe area layout guide. Aside from the legend, you might not be able to see the blue because it blends with the orange (safe area). Interestingly, the margin layout guide (blue) is just the safe area inset by 20 points in horizontally on the iPad and 16 points on the non-iPads. The readable content guide is identical to the layout margin guide on the non-iPads, but is significantly narrower on the iPad.

Here are the test results for landscape. Notice on the iPhone (middle), the safe area has inset on all four screen edges, avoiding the notch on one side and the home indicator on the bottom. They all leave enough space to be embedded in a UINavigationController.

Any subview that is not owned by the default view of a UIViewController will receive an 8 point margin for their subviews, if it were to be constrained to either the layout margin guide or the readable content guide of its parent view.

Landscape:

The frame of the safeAreaLayoutGuide of any view will not go out of the default view’s safeAreaLayoutGuide‘s frame, this means adding a subview to a view whose frame is within the safe area will receive 0 point margins, as opposed to the 8.

In conclusion, the layout margin guide and the readable content guide is really useful! When you want the default spacing around any view, you can just use the layout margin guide, and it automatically applies the appropriate spacing for you. When you are displaying large bodies of text, the readable content guide helps keep the text within an accepted maximum width so you don’t have to worry about it yourself. Both of these layout guides work on all devices.

If you’re interested in exploring more, here is the source that I used to generate these screens.

AppStore.apps.count += 1

I found an app that I was working on, but paused for a long time. In the past month or so, I have completed it. And now it is ready to meet with the world.

Motivation

Have you ever wanted to form a good habit and live with it? Well I have. I wanted an app that can remind me what habit I have accomplished for the day and what has not. For example, I wanted to read a book for 1 hour a day, and write a diary, and I want the app to remind me what I have accomplished and what is left to do. Yes… I can set a recurring event on my calendar app. But believe me, they have been there ever since I have owned a phone. And I will let you to guess how many times have I dismissed the notification, or deleted the event from the calendar altogether, and re-added the same recurring event back to the calendar app.

Moreover, how does the calendar app know that I have done it? Well the calendar app isn’t even made for that purpose. Well there is the Reminders app on iOS, you can set it to repeat daily and remind you at a specific time. True, and it almost does the job I want. But I wanted to keep track of my historical achievements, and look at my streak of the week, that is where “Disciplines” is born. It does all that.

The App

Disciplines is an app that can track personal, daily habits that you must develop in order to feel like a better person. All you need is a habit name, and it will be shown as part of the “Today” view. You can have multiple daily habits. To complete the habit, simply swipe to the left. In case you feel like the habit has been formed without the help of the app, you can swipe to the right, and the habit will be “archived”. Your past achievements are still kept in the “Achievement” view.

To delete the habit, you have to complete it at least once. As it shows up in the “Achievement” view, swipe to the left to reveal the option to delete the habit permanently.

To view how well you have done in the past week, go to “This Week” tab, and it will show you a completion percentage of all of the habits in the past 7 days.

Please try it out and give me feedback personally at info@monorailapp.com or directly on the App Store.

Creating UIColor from hex

There are times when you see a vibrant color on the web, or you wanna copy a color hex from Sketch, and you want to use this color in your app. The problem arises when you notice that none of the UIColor initializer overloads accept a hex as an argument. I spent an hour or two on this and created a UIColor extension which does just that. Let’s see how it is done.

The color hex is a hexadecimal that ranges from 0x0 to 0xFFFFFF, each pair of the digits from left to right correspond to the red, green and blue values that are out of 255, or 0xFF. To extract the blue color, simply perform AND on the color hex with 0xFF. For the remaining colors, we need to perform bit shifting in hexadecimal.

Bit Shifting in Hexadecimal

To understand bit shifting in hexadecimal, we need to understand how bit shifting is done in other radices. In binary, shifting to the right is equivalent to integer-dividing the value by 2.

110112 >> 1 = 11012

Therefore 27 >> 1 = 13.

In decimal, shifting to the right is equivalent to integer-dividing the value by 10.

7532 >> ?? = 753

Why did I put question mark here? That is because the bitwise operator >> shifts the preceding operand bitwise, not “decimalwise”. Unfortunately 10 is not a power of 2, we cannot use the bitwise operator to shift in decimal, because the binary value itself changes its “shape”, or its bit composition, during the shift.

Hexadecimal has a radix of 16, which is a power of 2, and we can use the bitwise operator to shift its bits. Knowing that shifting to the right by 1 is equivalent of division by 2, we simply need to get the quotient between the original and the shifted value. For example

0x001100 >> ? = 0x000110

That equation says in decimal 4352 >> ? = 272. The quotient of the two values is 16, which is 24. The question mark above is 4.

0x001100 >> 4 = 0x000110

Let’s try different values and see if we’re right.

0xFF0000 >> ? = 0x0FF000

That is, 16711680 >> ? = 1044480, we get 16 again after division. Okay. Let’s try by shifting 2 digits:

0xFF0000 >> ? = 0x00FF00

That is, 16711680 >> ?? = 65280, we get 256, which is 162 or (24)2, or 28. The question mark is 8. How about 3 digits?

0xFF0000 >> ?? = 0x000FF0

That is 16711680 >> ?? = 4080 = 4096, which is 163 or (24)3, or 212. The question mark is 12.

So we can conclude that in binary shifting, the number of digits you want to shift, say, x, is equal to the number after the >> operator. But in hexadecimal, that number can be determined by:

16x = (24)x = 24x

log2(24x) = 4x

In conclusion, each bit shift in hexadecimal is 4 times that of binary.

Extending UIColor

Going back to our original problem. We now know how to bit shift in hexadecimal, we can write something like:

import UIKit
extension UIColor {
convenience init(hex: Int) {
let red = CGFloat((hex & 0xFF0000) >> (4 * 4))/0xFF
let green = CGFloat((hex & 0x00FF00) >> (4 * 2))/0xFF
let blue = CGFloat(hex & 0x0000FF)/0xFF
self.init(red: red, green: green, blue: blue, alpha: 1)
}
}

We create a convenience initializer, and decompose the input hexadecimal number into red, green and blue components. Next we shift all of them to 2 digits, and divide the resulting value by 0xFF to get a CGFloat value between 0 to 1, which is what Swift wants in order to create a UIColor using its designated initializer.

To use this extension, we simply prepend the hex code with “0x” to tell Swift that this is a hex number. Fantastic! We can now copy these hex codes and use them directly in our code.

Value-driven Color

There are times when you want to display a graph of data and add meaningful colors based on their values. Such as the one below.

What we can do is to put a fixed number of colors, and use a switch statement with their case statement as ranges.

static func colorForPercent(_ percentage: Double) -> UIColor {
switch percentage {
case 0..<0.33:
return UIColor(hex: 0xE02020)
case 0.33..<0.66:
return UIColor(hex: 0xFA6400)
case 0.66..<1:
return UIColor(hex: 0xF7B500)
case 1:
return UIColor(hex: 0x6DD400)
default:
fatalError("Bad Input: percentage must satisfy 0 <= percentage <= 1")
}
}

What if we wanted a gradual change of colors, with a unique color corresponding to each value? Moreover, what if the y-values are not always 100?

My solution comes down in calculating each component of the RGB values of the resulting color, with the desired intermediate colors hard-coded.

extension UIColor {
static func colorForPercent(_ percentage: Double) -> UIColor {
switch percentage {
case 00.5:
return firstHalf(percentage: percentage * 2)
case 0.51:
return secondHalf(percentage: (percentage 0.5) * 2)
default:
fatalError("Bad Input: percentage must satisfy 0 <= percentage <= 1")
}
}
static fileprivate func firstHalf(percentage: Double) -> UIColor {
let begin = UIColor.systemGreen.cgColor.components!
let end = UIColor.systemYellow.cgColor.components!
return createColor(begin: begin, end: end, percentage: percentage)
}
static fileprivate func secondHalf(percentage: Double) -> UIColor {
let begin = UIColor.systemYellow.cgColor.components!
let end = UIColor.systemRed.cgColor.components!
return createColor(begin: begin, end: end, percentage: percentage)
}
static fileprivate func createColor(begin: [CGFloat], end: [CGFloat], percentage: Double) -> UIColor {
var colorDiff = begin
for i in 0 ..< 3 {
colorDiff[i] = begin[i] + (end[i] begin[i]) * CGFloat(percentage)
}
return UIColor(red: colorDiff[0], green: colorDiff[1], blue: colorDiff[2], alpha: 1)
}
}

This approach gets the job done, but from a design point of view, I personally like finite number of colors. In fact, the app that is shown in this blog post is currently using a finite number of colors. These colors are the template colors in the Sketch app, and I thought they looked beautiful.

“My Chinese Zodiacs” Submitted for Review

The long waited update to the Chinese Zodiac app is submitted for review. This update includes support for screens of iPhone X or later, and a redesign of the layout for easier access to the match feature.

In the process to update this app from version 1.0, many places of the code was refactored. First was to convert to Swift 4.2, then Swift 5. It wasn’t too difficult because Xcode does most of the conversion for you.

Then there was a major update to the storyboard. The “Add” button now takes you straight into adding a new person, where before you had to select whether to add a new person or start matching the list of friends. 2 weeks ago, the UITabBar was added on the bottom. Along with cute icons for each of the tabs on the tab bar. The pig graphic is the same pig used in the zodiac signs in the app, if that was not obvious. And the heart in the pig for the matching icon, its vector path is same as the heart shape on certain gift for a special someone this year.

Due to this change, lots of segues are removed, and hidden navigation bars are used to handle all of the inter-view controller navigation. Big, rounded-rectangle buttons will trigger the navigation actions. This is a huge improvement from version 1.0, because before, each button activated a new segue and a brand new UIViewController is created. This is a problem because if you navigate back and forth a couple of times, you would actually have a huge stack of view controllers held in memory, and eventually your iDevice will run out of memory and iOS will kill the app. This probably has something to do with memory cycles, and can probably be caught by using Instruments in Xcode. I say probably because I haven’t actually tested the app in Instruments. I should though. For next release, I promise!

Data Access for each person now has its own class “PersonDao”. It sounds like it is coming from Java, but I am indeed was just writing Java code at work last week.

Further more, the fetching of “persons” and the matching of list of “persons” is now in the background and will asynchronously update the UI once it is done.

Lastly, the UISegmentedControl has its default background color changed from white. The default color is gray, and it is not very pleasing to the eye when the text in front of them is white.

Here is a sneak peak!

In the next update. I’m planning to support iPads and easier birthday input.

Detecting Swift Versions in Online IDEs

As a young programming language, Swift changes frequently. It often brings us new features and deprecates old syntax. Sometimes when you run into an online IDE like LeetCode, HackerRank or Online Swift Playgrounds, you will often wonder: which version of Swift am I working with here? Well, look no further. This buddy on Stack Overflow uses a programmatic approach to determine the Swift version, quite cleverly. I’ve included the code below. 

Interestingly, Repl.it actually has the version number printed as soon as the IDE is initialized. Kudos for them!

#if swift(>=5.2)
print("Hello, Swift 5.2")

#elseif swift(>=5.1)
print("Hello, Swift 5.1")

#elseif swift(>=5.0)
print("Hello, Swift 5.0")

#elseif swift(>=4.2)
print("Hello, Swift 4.2")

#elseif swift(>=4.1)
print("Hello, Swift 4.1")

#elseif swift(>=4.0)
print("Hello, Swift 4.0")

#elseif swift(>=3.2)
print("Hello, Swift 3.2")

#elseif swift(>=3.0)
print("Hello, Swift 3.0")

#elseif swift(>=2.2)
print("Hello, Swift 2.2")

#elseif swift(>=2.1)
print("Hello, Swift 2.1")

#elseif swift(>=2.0)
print("Hello, Swift 2.0")

#elseif swift(>=1.2)
print("Hello, Swift 1.2")

#elseif swift(>=1.1)
print("Hello, Swift 1.1")

#elseif swift(>=1.0)
print("Hello, Swift 1.0")

#endif

Studying UXD – User Experience Design

The app is live, it does have an age limit of 4+ though.

Admittedly, at this point the app is design without any formal guidelines or any science of UX design. Everything in the app is based on how I imagined an app should look, and it was coded “as I feel like it”. Very little planning went into it prior to production.

With a course I’m taking right now, I am able to learn about foundations of UX design. First and foremost, UX design is way more than the user interface. It is only true that user interface is only part of the study of UX design. So what is included in UX design?

UX design is a 5-part process that can be summarized into:

  1. Strategy
    • The foundation of any user experience
    • Asks the question: what do users want and expect from the app?
    • Asks the question: how does the app fit with users’ other goals?
  2. Scope
    • Includes functional specifications – what does the app accomplish
    • Includes content requirements – what content is of value to users
  3. Structure
    • Includes interaction design – to create a structured experience of patterns and sequences that present appropriate options to users
    • Includes an information architecture – volume of content, along with how it it’s organized, arranged and prioritized
  4. Skeleton
    • Includes interface design – to determine how to best arrange and present visual elements for the user to interact with
    • Includes navigation design – to design onscreen elements allow users to move through tasks and information intuitively
  5. Surface
    • Includes the final visual design – to use colours, images, typography and effects to reinforce the meaning of the contents, guide the user through tasks and information and reduce cognitive load, enable recognition and increase intuitive learning

This course really gets you to think about how much thinking, planning and researching is done before you sit down at a computer and create a new project in Xcode. App creation for me was with the new project created and staring at the interface builder in Xcode.

Based on a more detailed study of these five areas of UX design, I will devise my very own design process and start talking to people about their app ideas.

 

 

App is Approved!

Amazingly, “My Chinese Zodiacs” has been approved and is ready for sale! I’m really happy about it!

Screen Shot 2017-08-30 at 1.09.02 AM

It sure is exciting to receive such an email, at least for the first time! Hopefully the app will be released soon so everyone in the world is able to download it! Woot!

My next steps are:

  1. Study UX Design
  2. Devise an app design process for freelance jobs
  3. Construct a proposal sheet for freelance jobs
  4. Learn about app monetization
  5. Perfect online presence by learning and doing social media marketing
  6. Continue to learn to code!

Expecting results before Christmas, fingers crossed!

App Submitted for Review

After changing the overall colour and adding some minor changes, I finally clicked that legendary “Submit for Review” button that I have always been dreaming to press.

Like any other apps, this submission does not mark the end of this app, but instead it is a new beginning, opening to the whole world to rate, review and criticize. As it receives more feedback, it will be updated and improved. Here is a nice little email I received from a sender labeled as “iTunes Store”.Screen Shot 2017-08-28 at 10.52.50 PM.png

As a first timer, I am really excited to see what kind of feedbacks will I be getting from Apple’s app reviewers, regardless of the outcome of the submission. For those of you who received TestFlight invite for version 1.1 build 5, the submitted version simply is build 6, which only includes the change from a “Universal” app to an “iPhone” app, because the app’s auto-layout works poorly on iPads, for now.

Plans for The Next Steps

I know I haven’t been blogging for a HUGE while now. I have been admittedly exploring different career options and cool stuff to do around Toronto. In the mean time, I have re-centered my career direction towards iOS development. I am once again back on track on becoming an iOS developer!

From the feedback I received from my friend WZ, my long-due Chinese Zodiac app is still not yet mature enough to be a “fully-featured, up-to-standards” iOS application. In the upcoming few days, I will be improving it from the following perspectives:

  1. UX and UI
  2. Importing contacts from the contacts app
  3. Following Apple’s Human Interface Guidelines closely

Deadline is set to be this Friday at 11:59PM! See how far I get!