Implement Keyboard Key Pop Animation in iOS 8 Keyboard Extension Implement Keyboard Key Pop Animation in iOS 8 Keyboard Extension ios ios

Implement Keyboard Key Pop Animation in iOS 8 Keyboard Extension


I would use a CAShapeLayer.

You can reset the shape layer's shape at any time, and even animate the change in shape to do something more elaborate than the Apple version.

Here is code for a playground that demonstrates a simple version of a class that accomplishes this:

import UIKitclass KeyPopView: UIView {  static let widthPadding : CGFloat = 5.0  static let leftOffset : CGFloat = -5.0  init(frame: CGRect, letters: [String]) {    super.init(frame: frame)    addLetters(letters)  }  required init(coder aDecoder: NSCoder) {    fatalError("init(coder:) has not been implemented")  }  override class func layerClass() -> AnyClass {    return CAShapeLayer.self  }  override func layoutSubviews() {    super.layoutSubviews()    var run : CGFloat = KeyPopView.widthPadding    for l in labels {      let s = sizeForLabel(l)      let mh = maxHeight(labels)      l.frame = CGRectMake(run, -mh, s.width, s.height)      run += s.width + KeyPopView.widthPadding    }  }  var shapeLayer: CAShapeLayer {    get {      return layer as! CAShapeLayer    }  }  var path: CGPathRef {    get {      return shapeLayer.path    }    set(nv) {      shapeLayer.shadowPath = nv      shapeLayer.path = nv    }  }  var labels : [UILabel] = [] {    willSet {      for l in labels {        l.removeFromSuperview()      }    }    didSet {      for l in labels {        addSubview(l)      }      path = keyPopPath(labels, cornerRadius: cornerRadius).CGPath    }  }  var cornerRadius : CGFloat = 4 {    didSet {      path = keyPopPath(labels, cornerRadius: cornerRadius).CGPath    }  }  override var backgroundColor: UIColor? {    set(newValue) {      shapeLayer.fillColor = newValue?.CGColor    }    get {      return UIColor(CGColor: shapeLayer.fillColor)    }  }  func keyPopPath(ls : [UILabel], cornerRadius: CGFloat) -> UIBezierPath {    let radius = CGSizeMake(cornerRadius, cornerRadius);    let f = CGRectMake(0, 0, frame.width + KeyPopView.widthPadding * 2, frame.height)    let mh = maxHeight(ls)    var b = UIBezierPath(roundedRect: CGRectMake(KeyPopView.leftOffset, -mh, widthForLabels(ls) - KeyPopView.leftOffset + KeyPopView.widthPadding, mh), byRoundingCorners: UIRectCorner.AllCorners, cornerRadii: radius)    b.appendPath(UIBezierPath(roundedRect: f, byRoundingCorners: UIRectCorner.BottomLeft | UIRectCorner.BottomRight, cornerRadii: radius))    return b  }  func addLetters(letters : [String]) {    labels = letters.map({(s: String) -> UILabel in      var l = UILabel()      l.text = s      return l    })  }  func widthForLabels(ls: [UILabel]) -> CGFloat {    return ls.reduce(0, combine: {(t, l) in t + sizeForLabel(l).width + KeyPopView.widthPadding}) + KeyPopView.widthPadding  }  func sizeForLabel(l: UILabel) -> CGSize {    return l.text!.sizeWithAttributes([NSFontAttributeName: l.font])  }  func maxHeight(ls: [UILabel]) -> CGFloat {    var m : CGFloat = 0;    for l in ls {      let h = sizeForLabel(l).height      m = m > h ? m : h    }    return m  }}//start with a gray background viewvar ba = UIView(frame: CGRectMake(0, 0, 300, 300))ba.backgroundColor = UIColor.grayColor()//add a mock "key"let key = UILabel()key.text = "a"key.textAlignment = NSTextAlignment.Centerkey.backgroundColor = UIColor.whiteColor()let size = key.text!.sizeWithAttributes([NSFontAttributeName: key.font])key.frame = CGRectMake(5, 0, size.width + 10, size.height)key.layer.cornerRadius = 5key.center = ba.centerba.addSubview(key)//add the initial keypopkey.hidden = true // the key's rounded corners aren't showing up correctly in my playground preview -- this shouldn't be necessaryvar k = KeyPopView(frame: CGRectMake(0, 0, size.width, size.height), letters: ["a"])k.backgroundColor = UIColor.whiteColor()ba.addSubview(k)k.center = CGPointMake(key.center.x - 5, key.center.y)ba//demonstrates resizing of the keypop view to accomdate more lettersk.addLetters(["a", "b", "c", "d", "e"])ba

In its current form, this class has many issues:

  • Letters are slightly off center
  • The frame of the view is used as the frame of the key that the pop begins from, not the actual frame of what is drawn.
  • It only supports left key pops
  • Several optionals are force unwrapped
  • The "stem" of the path used doesn't have rounded inner corners like the System Keyboard
  • Variables are named for brevity, not clarity

however this should provide a good basis for achieving what you want.


Might be easiest to just do the animation in photoshop or something that can output the animation frames as separate images, then animate a UIImageView (docs).

So just have the background of the popup thing animate in the above mentioned way, then can either make the letter fade in with the animation, or carefully animation the UILabel with the backgrounds animation