Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

ios - Making a UIButton with shape CAShapeLayer

So I'm making a kind of simple game based on hexagons. Here's what it looks like:

image

I've managed to draw the hexagons exactly the way I want them as CAShapeLayers, but I'd like to make them clickable. In short I would like to cast them somehow into UIButtons so I can track which one is selected via touchUpInside. The other way I can think of doing it is track touches and check if they were in the shape with tag, but it seems way to complicated. Below is my code:

        let screenSize: CGRect = UIScreen.mainScreen().bounds
        let screenWidth = screenSize.width
        let screenHeight = screenSize.height

        let radius : CGFloat = screenWidth/6

        var c = 0

        var counter = 0

        for j in 1...6 {
            for i in 1...3 {

                for x in 1...2 {

                    var center = CGPoint(x: CGFloat((i-1)*2)*radius+CGFloat(i-1)*radius, y: CGFloat((j-1)*2)*radius)

                    if (x==2) {
                        center.x = center.x+1.5*radius
                        center.y = center.y+radius
                    }



                    let shape = CAShapeLayer()
                    view.layer.addSublayer(shape)
                    shape.opacity = 0.5
                    shape.lineWidth = 2
                    shape.lineJoin = kCALineJoinMiter
                    shape.strokeColor = UIColor(hue: 0.786, saturation: 0.79, brightness: 0.53, alpha: 1.0).CGColor
                    shape.fillColor = UIColor(hue: 0.786, saturation: 0.15, brightness: 0.89, alpha: 1.0).CGColor


                    let path = UIBezierPath()
                    path.moveToPoint(CGPointMake(center.x-radius, center.y))
                    path.addLineToPoint(CGPointMake(center.x-radius/2, center.y-radius))
                    path.addLineToPoint(CGPointMake(center.x+radius/2, center.y-radius))
                    path.addLineToPoint(CGPointMake(center.x+radius, center.y))
                    path.addLineToPoint(CGPointMake(center.x+radius, center.y))
                    path.addLineToPoint(CGPointMake(center.x+radius/2, center.y+radius))
                    path.addLineToPoint(CGPointMake(center.x-radius/2, center.y+radius))

                    path.closePath()
                    shape.path = path.CGPath



                }


            }

        }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The other way I can think of doing it is track touches and check if they were in the shape with tag, but it seems way to complicated

Okay, but the problem is that you've chosen to do this with layers, and layers do not detect touches at all, so it's hard to see what other choice is open to you. You cannot "cast" a layer into a button; if you wanted buttons, or views that detect taps on themselves, you should have used buttons or views, not layers.

If you use a custom UIView, for example, it can use your shape layer as its layer and implement hit-testing to determine whether a tap falls within the shape layer's hexagon path. Here's an example to get you started:

class HexButton: UIView {

    var path: UIBezierPath!

    override class func layerClass() -> AnyClass {
        return CAShapeLayer.self
    }

    override init(frame: CGRect) {
        super.init(frame:frame)
        self.finishInitialization()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder:aDecoder)
        self.finishInitialization()
    }

    func finishInitialization() {
        let shape = self.layer as! CAShapeLayer
        shape.opacity = 0.5
        shape.lineWidth = 2
        shape.lineJoin = kCALineJoinMiter
        shape.strokeColor = UIColor(hue: 0.786, saturation: 0.79, brightness: 0.53, alpha: 1.0).CGColor
        shape.fillColor = UIColor(hue: 0.786, saturation: 0.15, brightness: 0.89, alpha: 1.0).CGColor

        let center = CGPoint(x:self.bounds.midX, y: self.bounds.midY)
        let radius = self.bounds.width/2.0

        let path = UIBezierPath()
        path.moveToPoint(CGPointMake(center.x-radius, center.y))
        path.addLineToPoint(CGPointMake(center.x-radius/2, center.y-radius))
        path.addLineToPoint(CGPointMake(center.x+radius/2, center.y-radius))
        path.addLineToPoint(CGPointMake(center.x+radius, center.y))
        path.addLineToPoint(CGPointMake(center.x+radius, center.y))
        path.addLineToPoint(CGPointMake(center.x+radius/2, center.y+radius))
        path.addLineToPoint(CGPointMake(center.x-radius/2, center.y+radius))

        path.closePath()
        shape.path = path.CGPath

        self.path = path

    }

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        return self.path.containsPoint(point) ? self : nil
    }

}

If you attach a tap gesture recognizer to that view, you will see that it fires only if the tap is inside the hexagon.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...