The Finnternet Like the Internet but with more me

Get Swifty: Accelerometer & Parallax Images

Accelerometers are one of the mobile features that might not get that much use but when it does, it usually gives cool results as you can see in the gif of the Parallax image example that we will cover below.

Input Accessory View

Using the accelerometers in iOS only takes four steps,

  • import Coremotion, the iOS framework for handling the accelerometer, gyroscope, pedometer, and environment-related events.
  • declare & initialize a CMMotionManager
  • create a function that you want to be called with the accelerometer updates
  • start listening for accelerometer updates

These steps can be seen implemented in the ViewController below

import CoreMotion

class ViewController: UIViewController {
    
    var motionManager: CMMotionManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        motionManager = CMMotionManager()
        motionManager.startAccelerometerUpdates(to: .main, withHandler: readAccelerometer)
    }
    
    func readAccelerometer(data: CMAccelerometerData?, error: Error?) {
        guard let accelerometerData = data else { return }
        
        // Access accelerometer data
        // X: accelerometerData.acceleration.x
        // Y: accelerometerData.acceleration.y
        // Z: accelerometerData.acceleration.z
    }
} 

Parallax

Now for one of my favorite uses of the accelerometer input, Parallax images. I remember when I first noticed the subtle effect on the iOS homescreen I found it so cool. Although this could be done using the accelerometer input above, iOS provides us with a simpler way using UIInterpolatingMotionEffect.

All you have to do is,

  • create a UIInterpolatingMotionEffect, specifying the property (keypath) you want to link the motion to and the type of motion you are interested in
  • set the min & max movement amounts allowed
  • create a UIMotionEffectGroup & set its motionEffectsapply to the UIInterpolatingMotionEffects you created
  • apply the motionEffectGroup to your view using addMotionEffect(UIMotionEffectGroup)

Here is a simple UIImageView extension that you can use to add the Parallax effect to any UIImageView by calling myImageView.parallax(). I should also note that to avoid seeing the background, you should set the UIImageView’s Content Mode to “Center”.

extension UIImageView {
    func parallax() {
        let min = CGFloat(-30)
        let max = CGFloat(30)
        
        let xMotion = UIInterpolatingMotionEffect(keyPath: "layer.transform.translation.x", type: .tiltAlongHorizontalAxis)
        xMotion.minimumRelativeValue = min
        xMotion.maximumRelativeValue = max
        
        let yMotion = UIInterpolatingMotionEffect(keyPath: "layer.transform.translation.y", type: .tiltAlongVerticalAxis)
        yMotion.minimumRelativeValue = min
        yMotion.maximumRelativeValue = max
        
        let motionEffectGroup = UIMotionEffectGroup()
        motionEffectGroup.motionEffects = [xMotion, yMotion]
        
        self.addMotionEffect(motionEffectGroup)
    }
}

Get Swifty: Input Accessory View

Have you ever used an app that adds a button to the top of the keyboard when you are typing in a textfield? My first thought was to detect the keyboard & shift the button from the bottom to be at the right height but thankfully Apple provides a much easier solution; input accessory views.

Input Accessory View

Achieving the setup seen above is as simple as programatically creating a button in your view controller’s viewDidLoad method & attaching it to the IBOutlet for your textfield.

class ViewController: UIViewController {

    @IBOutlet weak var inputTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let inputButton = UIButton(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 60))
        inputButton.backgroundColor = #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)
        inputButton.setTitle("Do something cool", for: .normal)
        inputButton.setTitleColor(#colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0), for: .normal)
        inputButton.addTarget(self, action: #selector(ViewController.somethingCool), for: .touchUpInside)
        
        inputTextField.inputAccessoryView = inputButton
    }
    
    @objc func somethingCool() {
        print("Completed a sweet bunny hop on your scooter!")
    }
}

Get Swifty: Add image to navigation bar title spot

When working with navigation bars, setting a text title is a cinch, but I wanted to set a logo instead. This ended up requiring a pretty short custom class.

Fixed Image Nav Item

Create a new Cocoa Touch file with the following code. Then apply this class to your navigation item.

class FixedImageNavigationItem: UINavigationItem {
    private let fixedImage : UIImage = UIImage(named: "logo.png")
    private let imageView : UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 37.5))

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
                imageView.contentMode = .scaleAspectFit
                imageView.image = fixedImage
             self.titleView = imageView
        }
}

Get Swifty: @IBDesignable

One thing that always annoyed me about using custom views was that the storyboard wouldn’t display the customizations I made. This means in order to make sure the textfield’s placeholder text color was right, I would have to build & run my app. This is where the descriptor @IBDesignable comes to the rescue! By adding @IBDesignable on the line above your custom view class & overriding the function prepareForInterfaceBuilder() to run your customizations, storyboard will evaluate & show the customizations made by that class.

@IBDesignable
class MyCustomTextField: UITextField {
    
    override func prepareForInterfaceBuilder() {
        customizeView()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        
        customizeView()
    }

    func customizeView() {
        // Add customizations here
    }
}

Get Swifty: Currency Textfield

When working on one of my recent projects I ran into the case where I had a textfield that represented a currency. Naturally, you want a currency symbol to prepend the text input, easy right? Wrong! Well maybe it’s not that hard (and there are libraries you can use that will do it for you), but it is harder than you would think. The user should be able to delete the numbers they inputted but not the symbol, the symbol needs to be stripped off when evaluating the input as a number, & the symbol has to be matched to their country.

Currency Textfield

I found this gem while watching some instructional videos & thought it was a great solution to this problem. The code in the following draw function creates a UILabel, sets it just inside the left side of the text field, does some visual stuff, & then uses a formatter to add the correct currency symbol.

override func draw(_ rect: CGRect) {
    let size: CGFloat = 20
    let currencyLabel = UILabel(frame: CGRect(x: 5, y: (frame.size.height / 2) - (size / 2), width: size, height: size))
    currencyLabel.backgroundColor = #colorLiteral(red: 0.8809662074, green: 0.8809662074, blue: 0.8809662074, alpha: 0.7980789812)
    currencyLabel.textAlignment = .center
    currencyLabel.textColor = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
    currencyLabel.layer.cornerRadius = 5.0
    currencyLabel.clipsToBounds = true
    
    let formatter = NumberFormatter()
    formatter.numberStyle = .currency
    formatter.locale = .current
    
    currencyLabel.text = formatter.currencySymbol
    
    addSubview(currencyLabel)
}