Tag Archives: swift

Multiple UIDynamicAnimators

In past apps, I tended to have one UIDynamicAnimator in my ViewController and that was that. UIDynamicAnimator allows you to use UIDynamics / effects on your UIViews.

The issue that I ran into was that removeBehavior(_:), which “Removes a specified dynamic behavior from a dynamic animator“, didn’t seem to work. I would keep track of specific UIDynamicBehavior instances and pass them as the argument for removeBehavior(_:) but it didn’t appear to remove the behavior.

What does work is calling removeAllBehaviors() on the UIDynamicAnimator. This is fine if you only have one UIView. But most likely, you have multiple UIViews & behaviors. Calling remove all on the only animator isn’t a good idea. That could leave UIViews frozen out of place.

Recently, I released a fun weekend app, Fun Faces. Browsing stack overflow, it occurred to me to use multiple UIDynamicAnimators. One for each UIView I wanted to animate. This worked for my use case, where calling removeAllBehaviors() doesn’t interrupt the other UIView’s behaviors (if any).

Using multiple UIDynamicAnimators isn’t an answer if you have multiple UIViews under the same animator with UICollisionBehavior or other effects that let the UIViews interact with each other.

Using CoreMotion deviceMotion to keep image level example (Xcode 8.3, Swift 3.1)

I’ve been playing around with CoreMotion since it is frankly so cool. I’ve followed NSHipster’s CMDevice​Motion post, but I made some changes to use the latest Swift v3.1. Below is sample code for using both the gyroscope and accelerometer to keep an image level when you rotate your phone.

//
//  ViewController.swift
//
//  Created by Rex on 4/22/17.
//

import UIKit
import CoreMotion

class ViewController: UIViewController {

    let interval = 0.01
    let imageFilename = "bg.jpg"
    let imageWidth = CGFloat(800)
    let imageHeight = CGFloat(1200)
    
    let manager = CMMotionManager()
    var imageView: UIImageView?

    override func viewDidLoad() {
        super.viewDidLoad()

        guard manager.isDeviceMotionAvailable else { return }
        
        setImageView()
        
        manager.deviceMotionUpdateInterval = interval
        let queue = OperationQueue()
        
        manager.startDeviceMotionUpdates(to: queue, withHandler: {(data, error) in
            guard let data = data else { return }
            let gravity = data.gravity
            let rotation = atan2(gravity.x, gravity.y) - .pi

            OperationQueue.main.addOperation {
                self.imageView?.transform = CGAffineTransform(rotationAngle: CGFloat(rotation))
            }
        })
    }
    
    func setImageView() {
        if let img = UIImage(named: imageFilename) {
            let iv = UIImageView(image: img)

            // center the image
            let x = (self.view.frame.width/2)-(imageWidth/2)
            let y = (self.view.frame.height/2)-(imageHeight/2)
            iv.frame = CGRect(x: x, y: y, width: imageWidth, height: imageHeight)
            
            self.view.addSubview(iv)
            self.imageView = iv
        }
    }
    
}

The setup is simple. Create a new Single View Application project in Xcode. You’ll need to add a JPG to the Assets.xcassets folder in the project. Replace the Viewcontroller with the code below and make sure to update the image filename, width, and height constants.

The code hopefully is straightforward. We make sure the CMMotionManager’s device motion is available. Then, we add the imageview (as the only UIView element we’re adding to the screen). We use an OperationQueue to process the rotation calculation off the main queue. Then we update the imageview with a transform on the main queue.

Standing on the Shoulders of Documentation

sprout123

Learning how to build a simple iOS app has not been bad. There’s a lot of learning how to find things in Xcode (protip: get a 2nd screen) and familiarizing myself with UIKit conventions. I completed the bitfountain iOS 7 course and have subscribed to more iOS newsletters than I care to admit.

At a meetup last year, I had a discussion about my choice to start with Objective-C. He asked me why I didn’t jump into Swift or use a tool like PhoneGap. Fast forward several months to today, I’m very happy I went with Objective-C. Whenever I am unsure how to do something in Objective-C, there are endless helpful blog posts and StackOverflow discussions out there. Even blog posts written before 2010 can be helpful. I am truly standing on the shoulders of all those heroic individuals who’ve tread down the path before me years ago.

With Swift, I’m sure there’s great documentation out there, but my guess is that Swift today (the beginning of 2015) cannot compete with the thoroughness of Objective-C edge cases discussed on the Internet.

Access to simple, basic questions like converting a NSUInteger to a NSNumber are essential for those just starting out. I’d like to use the example of an extremely beginner friendly resource, RailsCasts, which taught you how to use run of the mill gems, like Devise, and helped create a new generation of developers. Without a wealth of beginner accessible resources, a language or framework can’t grow or grow as fast.

iOS Programming

I’ve started learning iOS programming. Objective-C seems very low level, but it’s alright as an older object oriented language. Learning the Apple frameworks seems to the be tricky part. There’s a lot for me to learn with using Xcode (since I don’t normally use IDEs) and frameworks like Cocoa Touch.

I spoke to someone recently who suggested skipping Objective-C and going directly to Swift. Or even a tool like PhoneGap. Personally, I side with Aaron Hillegass’ take:

I have three messages for these people:

  • If you want to be an iOS developer, you will still need to know Objective-C.
  • Objective-C is easier to learn than Swift. Once you know Objective-C,
  • it will be easy to learn Swift.

To take a longer perspective on iOS, I want to build my foundation up from Objective-C to iOS. This is similar to how learning Ruby is critical for being a Rails developer.

With that said, I’m eager to get my hands dirty with iOS prototypes through different online courses.