Sunday, October 30, 2016

Drop Shadow on a UIView

Minimum Code

Views already have a black, three point drop shadow by default but you cannot see it because the opacity is set to zero.
 
myView.layer.shadowOpacity = 1
 
That all you need to get started to show the drop shadow.

Options

Reposition the Drop Shadow

 
// Reposition the drop shadow (center it with with CGSize.zero)
myView.layer.shadowOffset = CGSize.zero // Default is (0, -3)
 
 
myView.layer.shadowOffset = CGSize(width: 0, height: -5) // Top
myView.layer.shadowOffset = CGSize(width: 5, height: 0) // Right
myView.layer.shadowOffset = CGSize(width: 0, height: 5) // Bottom
myView.layer.shadowOffset = CGSize(width: -5, height: 0) // Left
myView.layer.shadowOffset = CGSize(width: 5, height: -5) // Top, Right
myView.layer.shadowOffset = CGSize(width: -5, height: -5) // Top, Left
myView.layer.shadowOffset = CGSize(width: 5, height: 5) // Bottom, Right
myView.layer.shadowOffset = CGSize(width: -5, height: 5) // Bottom, Left
 

Change Drop Shadow Size

 
// Increase the size of the drop shadow
myView.layer.shadowRadius = 6 // Default is 3
 

Change Drop Shadow Color

 
myView.layer.shadowColor = UIColor.blue.cgColor
 

Improve Performance

 
// Apple says: "...this property will usually 
//             improve rendering performance..."
myView.layer.shadowPath = UIBezierPath(rect: myView.bounds).cgPath

// Another way is to convert the drop shadow into a bitmap.
// Apple says: "...may attempt to cache and reuse..."
myView.layer.shouldRasterize = true
 

(Xcode 8, Swift 3.0)

Friday, October 28, 2016

Adding Done Button to Keyboard

In this example I use a UIToolBar to contain the done button but you can use any UIView to assign to inputAccessoryView.
 
class ViewController: UIViewController {

    @IBOutlet weak var nameTextField: UITextField!
    @IBOutlet weak var phoneNumberTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let keyboardToolBar = UIToolbar()
        keyboardToolBar.sizeToFit()
        
        let flexibleSpace = UIBarButtonItem(barButtonSystemItem: 
            UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        let doneButton = UIBarButtonItem(barButtonSystemItem: 
            UIBarButtonSystemItem.done, target: self, action: #selector(self.doneClicked) )
        
        keyboardToolBar.setItems([flexibleSpace, doneButton], animated: true)
        
        nameTextField.inputAccessoryView = keyboardToolBar
        phoneNumberTextField.inputAccessoryView = keyboardToolBar
    }

    func doneClicked() {
        view.endEditing(true)
    }
}
 

Here is an example of using a Navigation Bar:
 
let navItem = UINavigationItem()
let doneBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, 
    target: self, action: #selector(self.doneClicked))
navItem.rightBarButtonItem = doneBtn

let navBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: view.frame.width, 
    height: 44))
navBar.pushItem(navItem, animated: true)

nameTextField.inputAccessoryView = navBar
phoneNumberTextField.inputAccessoryView = navBar
 

(Xcode 8, Swift 3.0)

Wednesday, October 26, 2016

Animating a Constraint

You want to animate the "layoutIfNeeded()" function after setting the constant on the constraint.
 
centerXConstraint.constant = 0

UIView.animate(withDuration: 0.2) {
    self.view.layoutIfNeeded()
}
 
(Xcode 8, Swift 3.0)

Dismiss Keyboard on Touch

If you want to dismiss the keyboard when you touch anywhere outside a text field, choose one of these ways:

Dismiss keyboard in a view with no scrollview/tableview

 
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
}
 
(Note: This will not work on a scrollview or tableview.)


Dismiss keyboard when touching inside a scrollview/tableview

  1. Add a TapGestureRecognizer to your storyboard's scene
  2. Create an action outlet in your viewcontroller with the code below
 
@IBAction func TapGestureRecognizer_Action(_ sender: UITapGestureRecognizer) {
    view.endEditing(true)
}
 


All in code

 
override func viewDidLoad() {
    super.viewDidLoad()
    
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.endEditing))
    view.addGestureRecognizer(tapGesture)
}

func endEditing() {
    view.endEditing(true)
}
 
(Xcode 8, Swift 3.0)

Monday, October 17, 2016

Custom TableView Section Headers

There are two ways you can add custom tableview section headers:
  • Build a view in code
  • Dequeue a prototype cell from the storyboard

In both cases 2 delegate methods must be implemented:
  1. viewForHeaderInSection
  2. heightForHeaderInSection

Building a View in Code

 
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = UIView()
    view.backgroundColor = UIColor.orange
    
    let image = UIImageView(image: sectionImages[section])
    image.frame = CGRect(x: 5, y: 5, width: 35, height: 35)
    view.addSubview(image)
    
    let label = UILabel()
    label.text = sectionTitles[section]
    label.frame = CGRect(x: 45, y: 5, width: 100, height: 35)
    view.addSubview(label)

    return view
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 60
}
 

Dequeuing a Prototype Cell

 
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let cell = tableView.dequeueReusableCell(withIdentifier: "headerCell") as! HeaderCell

    cell.headerImage.image = sectionImages[section]
    cell.headerLabel.text = sectionTitles[section]

    return cell
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    switch section {
    case 0,2:
        return 45
    default:
        return 60
    }
}
 


(Xcode 8, Swift 3.0)

Tuesday, October 11, 2016

Table Headers and Footers

Drag and drop UIViews on to a UITableView on the storyboard.
Tip: Add a prototype cell to the table view first. Then drag and drop the UIView above the prototype cell for a header or below the prototype cell for the footer.

You can then remove the prototype cell after you are done adding the header and/or footer.


(Xcode 8, Swift 3.0)

Sunday, October 9, 2016

Adding a Visual Format Language Constraint

The code adds a vertical and horizontal constraint to a UIView that is already on the storyboard.
 
@IBOutlet weak var myView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()

    myView.translatesAutoresizingMaskIntoConstraints = false
    
    let views = ["myView" : myView!]
    
    let constraints = NSLayoutConstraint.constraints(withVisualFormat: 
        "H:|[myView]|", 
        options: [] , metrics: nil, views: views)
    NSLayoutConstraint.activate(constraints)
    
    let vconstraints = NSLayoutConstraint.constraints(withVisualFormat: 
        "V:|-[myView]-|", 
        options: [] , metrics: nil, views: views)
    NSLayoutConstraint.activate(vconstraints)
}
 

Note: When creating the dictionary (views) it is important to include the exclamation point on the view you are adding. Otherwise you will get an error such as "unrecognized selector sent to instance".

See this post for more examples of using the Visual Format Language.

(Xcode 8, Swift 3.0)

Saturday, October 1, 2016

Visual Format Language shown Visually

Step-by-step Visual Format Language by example
H
Horizontal Layout
H:[view(100)]
H:|-[view]
H:|-0-[view]
H:|-20-[view]
H:|-100-[view]-100-|
H:|-20-[view1(100)]-20-[view2]-20-|
V
Vertical Layout
V:[view(100)]
V:|-[view]
V:|-0-[view]
V:|-100-[view]-100-|

SwiftUI Search & Filter with Combine - Part 3 (iOS, Xcode 13, SwiftUI, 2...

In part 3 of the Searchable video series, I show you how to use Combine in #SwiftUI for the search and filter logic connected to the searcha...