Swift – UIView

Here are some notes on working with UIView. I try to cover the differences between frame and bounds, and how to position elements on the screen using frame, bounds, and center. There is a video example and corresponding files on Github: https://github.com/soggybag/View-Experiements

Views

Views are the visible elements that appear in your apps. Views can look like anything. They can have color, images and text. Views can detect user touch interactions. A view is always a rectangle. The contents can have an alpha mask to allow the view to appear as any shape.

UIView

UIView is the base class for all visible elements that might appear on the screen. Every UI element inherits from UIView. You can think all the UI elements as UIViews with special added features. For example UILabel is a specialized version of UIView that is meant to act as a simple text display. All of the UI elements are built on top of a UIView.

Make a UIView for yourself.

let box = UIView()

In order to see the the view it needs a size, position, and to be added as a subview of a view that is in the display stack. You may also need to set the color. A white view against a white background will be hard to find!

Frames, Bounds, and Rectangles

Views are rectangular. A rectangle where a view can draw itself, and a user can interact. A rectangle or rect defines the both the size and position of a rectangular area of the screen. A rect is defined by four properties: x, y, width, and height.

CGRect(x: 0, y: 0, width: 100, height: 100)

The CGRect class is used to define a rect. UIView defines the frame property as a rect. Setting the frame of a view sets the position and size of the view.

The frame property of a view is a CGRect that defines the size and position of the view in it’s super view‘s coordinate system. Think about this as the size and position in the world in which it’s exists.

The bounds property of a view is also a CGRect. The bounds defines the size and position of a view it’s own, or local, coordinate space.

box.frame = CGRect(x: 0, y:0, width: 100, height: 100)

This should produce a box 100 by 100 points in the upper left corner. NOTE: you may not be able to see the white box against the white background! Set the background color:

box.backgroundColor = UIColor.redColor()

Center, X, and Y

 

A view can be positioned through it’s center property. The center property is a CGPoint. CGPoint contains an x and a y property.

While the x and y of the frame position a view around it’s upper left corner, the center.x and center.y position a view around it’s center!  You can check this for yourself:

let box = UIView()
box.frame = CGRect(x: 0, y:0, width: 100, height: 100)
print(box.center) // (50.0, 50.0)

You can see the center shows x and y of 50 while we set the frame x and y to 0 and 0.

Subviews

All views act as a containers for other views. You can add any view as a subview to another view. You can think of this like creating layers or groups. Or like nesting html tags.

Add a view to another view with the addSubview() method:

let box = UIView()
box.frame = CGRect(x: 0, y:0, width: 100, height: 100)
box.backgroundColor = UIColor.redColor()
view.addSubview(box)

The block of code above, added to your viewDidLoad(), would produce a red box in the upper left corner of 100 by 100 points.

Nesting Views

Views stack, front to back, in the order they are added with addSubview() since addSubview() adds the new view in front of existing views. You can use these other methods to arrange views.

 

  • addSubView()
  • insertSubview(:atIndex)
  • insertSubView(:belowSubview)
  • insertSubview(:aboveSubview)
  • exchangeSubviewAtIndex(:withSubviewAtIndex)
  • bringSubviewToFront()
  • sendSubviewToBack()

Width and Height

Setting the width and the height can be confusing. These properties show up in several places. For example:

box.frame.width // get only! 
box.frame.size.width // get and set

While both of this properties return the same value, the first (frame.width) is get only! You can’t set it. The second (frame.size.width) is get and set. The same is true for height.

box.frame.height // get only! 
box.frame.size.height //get and set

This also applies to bounds.

box.bounds.width // get only! 
box.bounds.height // get only!
box.bounds.size.width // get and set
box.bounds.size.height // get and set

CGSize

CGSize is a type with two properties: width and height.

box.frame.size = CGSize(width: 100, height: 100)

 

Frame vs Bounds and Coordinate space

Each view supports its own coordinate space. Imagine that each view defines x:0 as the position of it’s left edge, and y:0 as it’s top edge. Frame defines the position and size of a view within it’s superview, while bounds defines location and height in a views own coordinate space.

Center

A view also has a center. This is a CGPoint that locates the view on the x and y axis around it’s origin. The origin should be in the center of a view by default.

Origin

The origin is a property of bounds, and sets the x, and y position around which the rectangle is drawn.

 

Swift – Simple Animations

Need to create simple animation? Use UIView.animateWithDuration() or one of the other similar methods. While this is fairly easy to use, it is bit cumbersome. Why not make a helper method to simplify your work?

  1. Imagine a method that takes a UIView as a an argument. Since all UI elements are sub classes of UIView you can pass any UI element.
  2. For convenience imagine all of the elements were created at the location where they will end their motion. This means our method will offset the element in the x and or y, then move it back to it’s starting point.
  3. To make the motion interesting and give us some controller we need to pass in the duration.
  4. If everything is moving at the same time things are dull, and some things are not possible. We need a delay.

Our method looks like this:

func animateThing(thing: UIView, offsetY: CGFloat, offsetX: CGFloat, time: NSTimeInterval, delay: NSTimeInterval) {
// some code here 
}

The parameters are

  • thing – a UIView or subclass of UIView, which is the thing to animate
  • offsetY – CGFloat the amount to offset in the y axis. This sets the starting point on the y axis, thing will move back to original position!
  • offsetX – CGFloat the amount to offset on the x axis.
  • time – NSTimeInterval, this can be a Double (0.5 for example), it sets the length of the animation in seconds
  • delay – NSTimeInterval, this sets the time to wait before beginning the motion.

A few points

  1. The offsetX, and offsetY can use positive or negative numbers. Negative values move the object left or up. Positive numbers move down, or right. These determine an offset, that places the object at a new position before the motion begins, the object will end its motion at it’s starting point.
  2. Time is set in seconds. Delay determines how long to wait before the motion begins. The total time of the animation will be time + delay.
  3. It’s probably best to call this function in viewWillAppear. This way the objects get positioned before we see the view, and the motion will be applied each time the view is shown.

Using an Extension

An extension allows you to add functions to existing classes. Rather than adding this function to each custom view controller we create, using an extension we can add an extension to the UIViewController class, and all ViewControllers will have the new function.

Add the first code example to your project in a file named extensions.swift. You’re done! The second code example shows some usage examples and is not required.