I have a CAShapeLayer with a fill color, and want to add an icon in the center of this shape:
var shape = CAShapeLayer()
shape.fillColor = UIColor(white: 0.90, alpha: 1).CGColor
var image = UIImage(named: "some_image")
shape.contents = image?.CGImage
This code does compile and does show the grey shape- but no image. :(
I looked into these posts, but I can't cast the CGImage like they do.
add UIImage in CALayer and Display an image or UIImage with a plain CALayer
Is there another way? Or a workaround to the id cast?
Full code:
ViewController.swift
import UIKit
class ViewController: UIViewController {
@IBOutlet var menuView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
let menu: CircularMenu = CircularMenu(frame: menuView.bounds, numberOfMenuItems: 4, hasProgressBar: false)
self.menuView.addSubview(menu)
}
}
CircularMenu.swift
import UIKit
// *** Helper methods start
func DegreesToRadians (value: Double) -> CGFloat {
return CGFloat(value * M_PI / 180.0)
}
func RadiansToDegrees (value: Double) -> CGFloat {
return CGFloat(value * 180.0 / M_PI)
}
// *** Helper methods end
class CircularMenu: UIControl {
var parent: UIViewController!
var centerButton: UIButton!
var menuButtonShapes = [CAShapeLayer]()
var menuButtons = [UIButton]()
var numberOfButtons: Double = 4
var bigSize: CGFloat = 300
var centerButtonSize: CGFloat = 100
var centerButtonPadding: CGFloat = 70
let paddingBetweenButtons = 1
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect, numberOfMenuItems: Int, hasProgressBar: Bool = false) {
self.init(frame: frame)
self.bounds = frame
self.bigSize = frame.width
self.centerButtonSize = bigSize/2
self.centerButtonPadding = bigSize/4-5
if hasProgressBar {
self.centerButtonSize -= 10
}
if numberOfMenuItems != 0 && numberOfMenuItems <= 10 {
self.numberOfButtons = Double(numberOfMenuItems)
}
// Draw center button
var centerButtonView = UIView(frame: CGRectMake(0, 0, centerButtonSize, centerButtonSize))
centerButtonView.backgroundColor = UIColor(red: 160.0/255, green: 197.0/255, blue: 25.0/255, alpha: 1)
centerButtonView.center = self.center;
centerButtonView.layer.cornerRadius = centerButtonSize/2
self.addSubview(centerButtonView)
self.centerButton = UIButton(frame: centerButtonView.bounds)
let degreesPerButton: Double = 360.0/numberOfButtons
// Draw button shapes
for (var i: Double = 1; i <= numberOfButtons; i++)
{
// Determine start and end radians of pizza slice
let startAngle = DegreesToRadians(degreesPerButton*i+degreesPerButton-Double(paddingBetweenButtons))
let endAngle = DegreesToRadians(degreesPerButton*i+Double(paddingBetweenButtons))
// Determine center and angle of slice
var buttonCenter = self.center;
var offsetDirection = (startAngle - endAngle)/2 + endAngle
// Shove slice outward to make space for inner padding
var offsetX = cos(offsetDirection)*tan(DegreesToRadians(Double(paddingBetweenButtons)))*bigSize/2
var offsetY = sin(offsetDirection)*tan(DegreesToRadians(Double(paddingBetweenButtons)))*bigSize/2
buttonCenter.x += offsetX
buttonCenter.y += offsetY
// Create mask for outer rim of slice to a circular form (from triangle to pizza slice)
let outerCircleRadius = bigSize/2;
var bigCircle = UIBezierPath(arcCenter: self.center, radius: bigSize/2, startAngle: startAngle , endAngle: endAngle, clockwise: false);
bigCircle.addLineToPoint(buttonCenter)
bigCircle.closePath()
// Take padding into consideration when creating mask
let tmpBigSizeX = (bigSize+2*abs(offsetX))
let tmpBigSizeY = (bigSize+2*abs(offsetY))
// Create mask for inner rim of slice to a circular form (from pizza slice to donut slice)
let smallSize = bigSize-centerButtonSize-centerButtonPadding
let innerCircleRadius = outerCircleRadius-bigSize/2/2;
var smallCircle = UIBezierPath(arcCenter: self.center, radius: smallSize, startAngle: 0 , endAngle: DegreesToRadians(360), clockwise: false);
// Apply masks for everything but the donut slice shape
var buttonShape = CAShapeLayer()
var maskLayer = CAShapeLayer()
var maskPath = CGPathCreateMutable();
CGPathAddRect(maskPath, nil, CGRectMake(outerCircleRadius-tmpBigSizeX/2, outerCircleRadius-tmpBigSizeY/2, tmpBigSizeX, tmpBigSizeY));
CGPathAddPath(maskPath, nil, smallCircle.CGPath);
maskLayer.path = maskPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
buttonShape.path = bigCircle.CGPath
buttonShape.mask = maskLayer
buttonShape.fillColor = UIColor(white: 0.90, alpha: 1).CGColor
// Add icons and labels to the button
var image = UIImage(named: "menu-icon_users_grey")
let imageSubLayer = CALayer()
imageSubLayer.contents = image?.CGImage
buttonShape.addSublayer(imageSubLayer)
// Save references to both shape and button
self.menuButtons.append(UIButton(frame: buttonShape.frame))
self.menuButtonShapes.append(buttonShape)
// Add shape to view
self.layer.addSublayer(buttonShape)
}
}
}
Lines of interest are in the bottom of the custom UIControl under the comment:
"Add icons and labels to the button"