Ответ 1
Я бы использовал CAShapeLayer
.
Вы можете reset форма слоя формы в любое время и даже изменить изменение формы, чтобы сделать что-то более сложное, чем версия Apple.
Вот код игровой площадки, демонстрирующий простую версию класса, которая выполняет это:
import UIKit
class 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 view
var 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.Center
key.backgroundColor = UIColor.whiteColor()
let size = key.text!.sizeWithAttributes([NSFontAttributeName: key.font])
key.frame = CGRectMake(5, 0, size.width + 10, size.height)
key.layer.cornerRadius = 5
key.center = ba.center
ba.addSubview(key)
//add the initial keypop
key.hidden = true // the key rounded corners aren't showing up correctly in my playground preview -- this shouldn't be necessary
var 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 letters
k.addLetters(["a", "b", "c", "d", "e"])
ba
В текущей форме этот класс имеет много проблем:
- Буквы слегка от центра.
- Кадр представления используется как кадр ключа, из которого начинается поп, а не фактический кадр того, что нарисовано.
- Он поддерживает только левые клавиши.
- Несколько опций - это разворот силы.
- "Шток" используемого пути не имеет закругленных внутренних углов, таких как системная клавиатура
- Переменные называются для краткости, а не ясности.
однако это должно стать хорошей основой для достижения желаемого.