iOS 13 & Swift 5 - Udemy [Course]
Section 1: Getting Started with iOS 13 and Swift 5.1
1. Useful resources
https://www.appbrewery.co/p/ios-course-resources/
13. Getting set up with Xcode
Check you have enough space on disk
Make sure MacOS is 10.15+
Section 2: Xcode Storyboards and Interface Builder
17. Let’s Create a Brand New Xcode Project
Create a new Project
Choose a template: Application - Single View App. Because other views can be added later on.
Options: Organization identifier - reverse domain name (e.g. com.yuexit). Language - Swift. User interface - Storyboards (to begin with). Leave checkboxes unchecked.
19. Let’s Design the User Interface!
LaunchScreen.storyboard: screen that shows up on the first launch of app.
Design on the Main.storyboard.
View attributes: background (useful resource:
Adding components: “+ (library)” on right top. Drag them to the Main.storyboard.
Layers: first in list = bottom, last = top
20. Let’s Incorporate Some Image Assets
Drag custom images to Assets.xcassets. Image view attributes: image - your image.
Image size and names: image.png, image@2x.png, image@3x.png (online tool:
21. How to Design and Add an App Icon
Design resource:
Icon image autogeneration:
23. Run Your App on Your iPhone or Simulator
iPhone: Xcode preferences - Accounts - add Apple ID. Make sure iPhone iOS version matches Xcode version (iOS 13.x to Xcode 11.x). Connect iPhone via USB or same WiFi.
Simulator: Choose device/model on left top. Play button on left top.
Section 4: Swift Programming Basics - Collections, Constants & Variables
36. Cloning from GitHub and How to Download the L.A.B. Project Stubs
To clone from GitHub: Xcode menu - Source Control - clone - enter git address.
37. How to Design Your App
To copy a component, hold “option” and drag it.
38. Let’s Link Our Design to Our Code
Open editor assistant: right top “Adjust Editor Options” - Assistant.
Hold “control” and drag from component to inside “class ViewController: UIViewController”.
Do not rename IBOutlet names directly, or the connection will be broken. To fix it, right click the component, delete the outlet, and reconnect them by dragging.
To correctly rename IBOutlet, right click the IBOutlet name, refactor, rename.
To set view image: outletXXX.image = imageliteral. Then double click imageliteral to set image.
39. Responding to User Interactions with IBActions
Open editor assistant: right top “Adjust Editor Options” - Assistant.
Hold “control” and drag from component to inside “class ViewController: UIViewController”.
42. Storing Data using Variables and Arrays
Array: [ element1, element2, … ]
Print: print(“some text (some variable)”)
46. How to Randomise the Dice Images
Random number: Int.random(in: 0..5)
Random element of an array: someArray.randomElement()
Constant variable: let someVar = someValue
Variable variable: var someVar = someValue
Section 6: Auto Layout and Responsive UIs
65. Setting Constraints and working with the Safe Area
Adding constraints: bottom right - Add constraints.
Super view, safe area and margin.
67. Working with Containers and Subviews
To embed components into a view:
-
Create a view and drag components under it.
-
Choose components - menu - editor - embed in - view.
-
Choose components - bottom right - embed in - view.
To rename a view: right - identity - label.
68. Stack Views
Put related components into a stack view. They can be arranged automatically.
Section 7: Using and Understanding Apple Documentations
76. The 5 Step Approach to Solve Any Programming Problem
-
Google
-
Stack Overflow
-
Implements
-
Docs (hold “option” and click a word to open Apple Developer Documentations)
-
Customise
79. Linking Multiple Buttons to the Same IBAction
Drag from the dot at the left of IBAction to all related buttons.
80. Functions with Inputs and Type Inference
@IBAction func keyPressed(_ sender: UIButton) {
playSound(soundName: sender.currentTitle!)
}
func playSound(soundName: String) {
let url = Bundle.main.url(forResource: soundName, withExtension: "wav")
player = try! AVAudioPlayer(contentsOf: url!)
player.play()
}
func divide(n1: Int, n2: Int){
let n3 = Double(n1)/Double(n2)
print(n3)
}
Section 8: Intermediate Swift Programming - Control Flow and Optionals
87. Setting up the Egg Timer Project and Linking the Storyboard and ViewController
To solve label text overflow problem: change “Lines” to 0 (unlimited lines), make “Autoshrink - Minimum Font Size” smaller (so font automatically downsizes when overflow).
90. Conditional Statements Challenge Solution
if else:
if hardness == 1 {
statement1
} else if hardness == 2 {
statement2
} else {
statement3
}
switch case:
switch hardness {
case 1:
statement1
case 2:
statement2
default:
statement3
}
dictionary:
let eggTimes = ["Soft": 5, "Medium": 7, "Hard": 12]
98. Using the 5 Step Approach to Debug our App
-
What do you expect your code to do?
-
What happened instead?
-
What does your expectation depend upon?
-
How can we test the things our expectations depend on?
-
Fix our code to make reality match expectations
Section 9: iOS App Design Patterns and Code Structuring
109. Implementing MVC and Understanding Parameter Names
MVC:
-
Model: Question.swift (data)
-
View: Main.storyboard
-
Controller: ViewController.swift
In model,
import Foundation
struct Question {
let text: String
let answer: String
init(q: String, a: String) {
text = q
answer = a
}
}
//To initiate a Question structure:
//let quiz = Question(q: "A slug's blood is green.", a: "True")
Functions with external and internal parameters:
func someFunction(parameter: Int){
statement
}
func someFunction(par parameter: Int){
statement
}
func someFunction(_ parameter: Int){
statement
}
someFunction(parameter: myParameter)
someFunction(par: myParameter)
someFunction(myParameter)
Functions with an output:
func getMilk(money: Int) -> Int{
let change = money - 2
return change
}
Inside the struct, if a property is changed, the func
should be mutating
mutating func checkAnswer(userAnswer: String) -> Bool {
if userAnswer == quiz[questionNumber].answer {
score += 1
return true
} else {
return false
}
}
Section 11: Advanced Swift Programming - Classes, Inheritance & Advanced Optionals
132. Structs vs Classes
struct MyStruct {}
-
immutable
-
passed by value
class MyClass: SuperClass {}
-
passed by reference
-
inheritance
134. How to Create a UI Programatically and Pass Data between ViewControllers
Create a UI:
let label = UILabel()
label.text = "..."
label.frame = CGRect(...)
view.addSubview(label)
Present and pass data between view controller:
let secondVC = SecondViewController()
secondVC.bmiValue = ...
self.present(secondVC, animated: true, completion: nil)
135. Segues and Navigation for Multi-Screen Apps
Create new view controller: File - New file - Cocoa Touch Class (contains UIKit etc.)
Link swift file to view controller: choose the screen relate to new view controller - right “identity” - Class - your new view controller.
Create a segue: hold “control”, drag from first ViewController to the second one.
performSegue(withIdentifier: "goToResult", sender: self)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToResult" {
let destinationVC = segue.destination as! ResultViewController
destinationVC.bmiValue = calculatorBrain.getBMIValue()
destinationVC.advice = calculatorBrain.getAdvice()
destinationVC.color = calculatorBrain.getColor()
}
}
Go back to previous view: dismiss()
137. [Swift Deep Dive] Optional Binding, Chaining, and the Nil Coalescing Operator
String
and String?
(optional) are totally different data types.
-
Force Unwrap:
optional!
. Must make sure the optional will never be nil when it’s used. -
Check for nil value:
if optional == nil {} else {}
-
Optional Binding:
if let safeOptional = myOptional { use safeOptional }
-
Nil Coalescing Operator:
optional ?? defaultValue
-
Optional Chaining:
optional?.property, optional?.method()
Section 13: Networking, JSON Parsing, APIs and Core Location
154. Dark Mode and Working with Vector Assets
SF symbols: free, by Apple.
If choose colors provided by system, it will adapt to dark mode automatically.
Custom color that adapt to dark mode: Assets.xcassets - add new color sets - set colors - give it a name and use it.
PDF can be used as image. Image set - drag the pdf to 1x - Resizing: preserve vector data - Scales: single scale
155. Learn to use the UITextField
//UITextFieldDelegate is a protocol, not a class
extension WeatherViewController: UITextFieldDelegate {
//if search button is pressed
@IBAction func searchPressed(_ sender: UIButton) {
searchTextField.endEditing(true)
}
//if keyboard enter is pressed
//somewhere: @IBOutlet weak var searchTextField: UITextField!
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
searchTextField.endEditing(true)
return true
}
//if any of the text field end editing
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if textField.text != "" {
return true
} else {
textField.placeholder = "Type something"
return false
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
if let city = searchTextField.text {
weatherManager.fetchWeather(cityName: city)
}
searchTextField.text = ""
}
}
158. An Example of Protocols and Delegates in Practice
Use Delegate Design Pattern to maximize code re-usage.
//file: SignalProcessor.swift
//can be used by any view controller
protocol SignalProcessorDelegate {
//the VC uses this file must implements these functions:
func output()
}
class SignalProcessor {
//who takes over afterward:
var delegate: SignalProcessorDelegate?
var outputString: String?
//this is where VC functions are called:
func doesSomething(){
print("Signal received.")
outputString = "Some results"
delegate?.output()
}
}
//file: ViewController.swift
class ViewController {
var signalProcessor = SignalProcessor()
override func viewDidLoad(){
//access to the processor
signalProcessor.delegate = self
}
//other regular things
}
//implement required functions related to SignalProcessor
extension ViewController: SignalProcessorDelegate {
func output(){
//utilize properties of SignalProcessor
print(signalProcessor.outputString)
}
}
160. Use the URLSession for Networking
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
//while weather data is retrieving in background,
//update the user interface in foreground so that app won't freeze
DispatchQueue.main.async {
self.temperatureLabel.text = weather.temperatureString
self.conditionImageView.image = UIImage(systemName: weather.conditionName)
self.cityLabel.text = weather.cityName
}
}
func performRequest(with urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
//task starts but immediately suspends...
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
self.delegate?.didFailWithError(error: error!)
return
}
if let safeData = data {
if let weather = self.parseJSON(safeData) {
self.delegate?.didUpdateWeather(self, weather: weather)
}
}
}
//real start of task
task.resume()
}
}
161. [Swift Deep Dive] Closures
let array = [1, 2, 3, 4, 5]
func addOne(n1: Int) -> Int {
return n1 + 1
}
array.map(addOne) //function as parameter
array.map((n1: Int) -> Int { //anonymous function
return n1 + 1
})
//use closure to be one-line function
array.map({(n1: Int) -> Int in return n1 + 1 })
array.map({(n1) in n1 + 1 }) //type Inference
array.map({$0 + 1}) //$0 para_1, $1 para_2...
array.map(){$0 + 1}
array.map{$0 + 1} //if function is last para, trailing
162. JSON Decoding
//file: WeatherData.Swift
import Foundation
struct WeatherData: Codable {
let name: String
let main: Main
let weather: [Weather]
}
struct Main: Codable {
let temp: Double
}
struct Weather: Codable {
let description: String
let id: Int
}
//decode JSON
func parseJSON(_ weatherData: Data) -> WeatherModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
let id = decodedData.weather[0].id
let temp = decodedData.main.temp
let name = decodedData.name
let weather = WeatherModel(conditionId: id, cityName: name, temperature: temp)
return weather
} catch {
delegate?.didFailWithError(error: error)
return nil
}
}
163. Create a WeatherModel and Understand Computed Properties
Computed properties:
struct WeatherModel {
let temperature: Double
//computed property based on other properties
var temperatureString: String {
return String(format: "%.1f", temperature)
}
164. Typealiases and a Protocols and Delegate Challenge
Typealiases
struct WeatherData: Decodable, Encodable {
...
}
//also
struct WeatherData: Codable {
...
}
169. Using Extensions to Refactor the ViewController
Auto completion of frequently used code: Select the code - right click - Create code snippet - Completion: YourChoice. Use <#something#> for placeholder.
170. Using CoreLocation to get Location Data
import UIKit
import CoreLocation
class WeatherViewController: UIViewController {
var weatherManager = WeatherManager()
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
//modify plist
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
weatherManager.delegate = self
}
}
extension WeatherViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
locationManager.stopUpdatingLocation()
let lat = location.coordinate.latitude
let lon = location.coordinate.longitude
weatherManager.fetchWeather(latitude: lat, longitude: lon)
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
}
Section 15: Firebase Cloud Firestore, TableViews and Cocoapod Dependencies
187. Navigation Controller Stacks and Segues
Add navigation bar on top of screen: Select root ViewController - top menu Editor - Embed in - Navigation Controller
188. Typing Animations, Timers and For Loops
Letters in a String can be accessed by in
:
let astring = "sentence"
for letter in astring {
print(letter)
}
192. Cocoapods Installation Instructions
sudo gem install cocoapods
pod setup --verbose
pod --version
193. How to Install a Pod to your Project
cd YOUR_PROJECT_DIR
pod init
Open the newly created file named Podfile with Xcode. Edit it according to library installation manual.
pod install
To remove a Pod, delete the line in Podfile, pod install
again.
200. Logging Out Users
Drag Bar Button Items to the navigation bar.
To get straight back to root ViewController: navigationController?.popToRootViewController(animated: true)
To hide ‘Back’ button: navigationItem.hidesBackButton = true
201. Using a Constants File and Understanding the static Keyword
Minimize String typing by using a Constants file:
struct K { //or class
let instanceProperty = "Must create an instance before use"
static let typeProperty = "Can be used as 'K.typeProperty' straight away"
struct BrandColors {
static let purple = "BrandPurple"
}
struct FStore {
static let collectionName = "messages"
}
}
202. How to use a UITableView and Create a Message Model
To use a Table View (in which items arranged as a list), drag one Table View and ONE Table View Cell to the screen. Adjust the size of Table View.
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
}
}
extension ChatViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let message = messages[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath) as! MessageCell
cell.label.text = message.body
//This is a message from the current user.
if message.sender == Auth.auth().currentUser?.email {
cell.leftImageView.isHidden = true
cell.rightImageView.isHidden = false
cell.messageBubble.backgroundColor = UIColor(named: K.BrandColors.lightPurple)
cell.label.textColor = UIColor(named: K.BrandColors.purple)
}
//This is a message from another sender.
else {
cell.leftImageView.isHidden = false
cell.rightImageView.isHidden = true
cell.messageBubble.backgroundColor = UIColor(named: K.BrandColors.purple)
cell.label.textColor = UIColor(named: K.BrandColors.lightPurple)
}
return cell
}
}
203. Customising Cells in a TableView using a .xib File
Create a Cocoa Touch Class file - Subclass of UITableViewCell, also create xib file - Design the cell in xib file.
Make sure there is no prototype cell left in the table view. Match cell identifier and file name. Register table view with the designed cell:
class ChatViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: K.cellNibName, bundle: nil), forCellReuseIdentifier: K.cellIdentifier)
}
In the cellNibName.swift file:
import UIKit
class MessageCell: UITableViewCell {
@IBOutlet weak var messageBubble: UIView!
@IBOutlet weak var label: UILabel!
@IBOutlet weak var rightImageView: UIImageView!
@IBOutlet weak var leftImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
messageBubble.layer.cornerRadius = messageBubble.frame.size.height / 5
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Set cell label lines to 0, so that label adapts to unlimited number of lines.
204. [Swift Deep Dive] Casting as? as! as is and understanding Any
is
if var1 is SomeType {
print("var1 is SomeType")
}
as!: Forced downcast
let var1 = varOfClassA as! SubclassOfClassA
as?: Downcast to Optionals
if let var1 = varOfClassA as? SubclassOfClassA {
...
}
as: Upcast
let var1 = varOfSubclass as! SuperClass
Any: All objects, which includes
AnyObject: Objects derived from classes, which includes
NSObject: Foundation objects
205. Database setup and Saving Data to Firestore
@IBAction func sendPressed(_ sender: UIButton) {
if let messageBody = messageTextfield.text, let messageSender = Auth.auth().currentUser?.email {
db.collection(K.FStore.collectionName).addDocument(data: [
K.FStore.senderField: messageSender,
K.FStore.bodyField: messageBody,
K.FStore.dateField: Date().timeIntervalSince1970
]) { (error) in
if let e = error {
print("There was an issue saving data to firestore, \(e)")
} else {
print("Successfully saved data.")
DispatchQueue.main.async {
self.messageTextfield.text = ""
}
}
}
}
}
207. Listening for Updates on Firestore
func loadMessages() {
db.collection(K.FStore.collectionName)
.order(by: K.FStore.dateField)
.addSnapshotListener { (querySnapshot, error) in
self.messages = []
if let e = error {
print("There was an issue retrieving data from Firestore. \(e)")
} else {
if let snapshotDocuments = querySnapshot?.documents {
for doc in snapshotDocuments {
let data = doc.data()
if let messageSender = data[K.FStore.senderField] as? String, let messageBody = data[K.FStore.bodyField] as? String {
let newMessage = Message(sender: messageSender, body: messageBody)
self.messages.append(newMessage)
DispatchQueue.main.async {
self.tableView.reloadData()
let indexPath = IndexPath(row: self.messages.count - 1, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: false)
}
}
}
}
}
}
}
211. The ViewController Lifecycle Explained
viewDidLoad(): only called once, when view is created
viewWillAppear()
viewDidAppear()
viewWillDisappear()
viewDidDisappear(): view is not deleted, user just cannot see it
Section 17: SwiftUI and Declarative Programming
221. How to Build a SwiftUI App From Scratch
Set background and overlays:
ZStack{
Color(Color.black) //or
Image("background")
.resizable()
.edgesIgnoringSafeArea(.all)
Text("Some Text")
}
Vertical stack:
VStack {
Image("diceeLogo")
Spacer() //push other components to the edge
HStack {
DiceView(n: leftDiceNumber)
DiceView(n: rightDiceNumber)
}
.padding(.horizontal) //leave room between it and outer container
Extract reusable codes:
struct DiceView: View {
let n: Int
var body: some View {
Image("dice\(n)")
.resizable()
.aspectRatio(1, contentMode: .fit)
.padding()
}
}
Managing state. When the variable changes, the related components in struct ContentView will update automatically.
@State var leftDiceNumber = 1
@State var rightDiceNumber = 1
Button functions:
Button(action: {
self.leftDiceNumber = Int.random(in: 1...6)
self.rightDiceNumber = Int.random(in: 1...6)
}) {
Text("Roll")
.font(.system(size: 50))
.fontWeight(.heavy)
.foregroundColor(.white)
.padding(.horizontal)
}
.background(Color.red)
Section 18: Git, GitHub and Version Control
239. Version Control Using Git and the Command Line
#Initiate Git
git init
#Checking file changes
git status
#Add files to staging area (to track changes)
git add fileA
git add .
#Remove files from staging area
git rm --cached -r .
#Commit the change (use present tense)
git commit -m "Message"
#See past commits
git log
#Compare current file to last commit
git diff fileA
#Roll back to last commit
git checkout fileA
#Add remote repository ('origin' as a name convention)
git add remote origin https://somesite/projectA.git
#Sync local repo to remote repo
git push -u origin master
#Create new branch
git branch new-branch
#See which branch we are currently on
git branch
#Change to other branch
git checkout new-branch
#Merge branches
git checkout master
git merge new-branch
242. Gitignore
Common .gitignore: github/gitignore
Section 19: Local Data Persistance - User Defaults, Core Data and Realm
255. Persistent Local Data Storage Using UserDefaults
Save data of standard object (Strings, Arrays etc.) into plist:
import UIKit
let defaults = UserDefaults.standard
defaults.set(0.24, forKey: "Volume")
defaults.set(true, forKey: "MusicOn")
defaults.set("Jane", forKey: "UserName")
defaults.set(Date(), forKey: "AppLastOpenedByUser")
let array = [1,2,3]
defaults.set(array, forKey: "myArray")
let dictionary = ["name": "John"]
defaults.set(dictionary, forKey: "MyDictionary")
let volume = defaults.float(forKey: "Volume") // 0.24
let appLastOpen = defaults.object(forKey: "AppLastOpenedByUser")
let myArray = defaults.array(forKey: "MyArray") as! [Int]
let myDict = defaults.dictionary(forKey: "myDictionary")
257. [Advanced Swift] The Swift Singleton Object
Singleton Pattern is a pattern that ensures that there is only ever one single instance of a class, such as UserDefaults.standard
.
260. [Advanced Swift] The Swift Ternary Operator
var1 = condition ? valueIfTrue : valueIfFalse
263. Encoding Data with NSCoder
class Item: Codable {
var title: String = ""
var done: Bool = false
}
var itemArray = [Item]()
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("Items.plist")
let encoder = PropertyListEncoder()
do{
let data = try encoder.encode(self.itemArray)
try data.write(to: dataFilePath!)
} catch {
print(error)
}
264. Decoding Data with NSCoder
func loadItems() {
if let data = try? Data(contentsOf: dataFilePath!) {
let decoder = PropertyListDecoder()
do {
try itemArray = decoder.decode([Item].self, from: data)
} catch {
print(error)
}
}
}
265. Introduction to Databases
Methods and Uses:
-
UserDefaults: Quickly persist small bits of data
-
Codable: Flash freeze custom objects
-
Keychain: Save small bits of data securely
-
SQLite: Persist large amount of data and query it
-
CoreData: Object-oriented database
-
Realm: a faster and easier database solution
266. How to Set up and Configure Core Data
When create a project, check “use coreData”. Or, add Core Data data model later to existing project.
273. How to Implement a UISearchBar and Querying with Core Data
Add a search bar. “Option + Drag” the search bar to view controller, add delegate.
Section 20: In-App Purchases and Apple StoreKit
300. Setup Your In-App Purchase on App Store Connect
Logon to Apple Developer website.
Add a new App ID.
Go to App Store Connect, check out informs.
Fill Agreements, Tax and Banking.
My Apps - In-App Purchases
Section 33: Bonus: The Complete App Design Course
441. Understanding the Mood of Your Colour Palette
Red: Love, energy, intensity
Yellow: Joy, intellect, attention
Green: Freshness, safety, growth
Blue: Stability, trust, serenity
Purple: Loyalty, wealth, femininity
442. How to Combine Colours to Create Colour Palettes
Use nearby colors in the color wheel: analogous colors. Harmonious, can be stared at for a long time.
Use opposite colors in the color wheel: complementary colors. Attention grabing, but hard to last.
Use nearby colors beside the complementary colors: split colors. Stands out without being too contrast.
Use equally spaced colors in the color wheel: triadic colors. Balanced, old fashioned.
Use single color in the color wheel, but use lightness/darkness to emphasize the elements: monochromatic.
Useful resources:
-
Curated color palettes: http://www.colorhunt.co
-
Good colors for iOS: https://flatuicolors.com
-
Good colors for Android: https://www.materialpalette.com
-
Color picker in web browser: https://www.colorzilla.com
449. How to Combine Fonts Like a Pro
Consider readability.
Match with similar moods and time-eras. Contrast serif/sans-serif and weights.
453. The Importance of Alignment
Use as few alignment guide lines as possible.
454. What is Good Practice in Interaction Design
Keep real world in mind to help user understand how to use your app.
456. The Many Ways of Designing Text Overlays
Use opaque overlay to make texts standing out.
457. How to Be an Attention Architect
Use contrast
459. What is User Experience (UX) Design?
Keep the design flexible to suit real user experience.
460. Usability
Keep core function as simple to use as possible.
461. Asking for Permissions
Ask for small thing first, so that the user may agree on bigger thing later.
462. User Profiling
Give the user full personality and tailor your app to her/him.
463. Form vs. Function
Function should always come before form.
464. Consistency
Consistency in look and function.
465. Simplicity
Make it simple, add things later if necessary.
466. Don’t Make Me Think
Don’t front-load lots of info, give a hint just when it’s needed. Don’t make users confused.
-
Onboarding 3min
-
Idiot Boxes 4min
-
Further Reading on User Experience Design 1min
-
Android vs. iOS Design 3min
-
Navigation 3min
-
The Devil is in the Details 1min
-
Differences in Icon Design 1min
-
Flat Design vs. Material Design 3min
-
Differences in Establishing Visual Hierarchy 1min
-
iOS and Android Design Guidelines 3min Resources
-
Step1 - Design Patterns and Colour Palettes 3min
-
Where to Find Design Patterns and Colour Palettes 1min
-
Step 2 - How to Create a User Flow Diagram 8min
-
Step 3 - How to Create Wireframes 11min
-
Wireframing Resources 1min
-
Step 4 - How to Create Professional Mockups 5min
-
Tools for Creating Mockups 1min
-
How to Use Sketch to Create Mockups 15min Resources
-
[Optional] Watch me Create a Mock up Using Sketch 46min
-
How to Use Canva to Create Mockups 4min Resources
-
Your Turn to Create Your Own Mockups 2min
-
Tools and Resources for Creating Mockups 1min
-
Step 5 - How to Create an Animated App Prototype 4min
-
Tools and Resources for Creating Prototypes 1min
-
Prototyping with Keynote 8min
-
Prototyping with Marvel 5min Resources
-
Your Turn to Create a Prototype 1min Resources
-
Where to Find Free-For-Commercial-Use Image As… 1min
-
Where to Find Free-For-Commercial-Use Icons 1min
-
How to Keep Designing and Improving 1min Resources
-
Tip from Angela - Step Up to Challenges