Search code examples
iosswiftcgaffinetransformswift-playground

Playground code: AffineTransform and AnchorPoint don't work as I want


I want to shrink a triangle downward as below:

enter image description here

But the triangle shrink upward as below:

enter image description here

The transform code is below:

layer.setAffineTransform(CGAffineTransformMakeScale(1.0, 0.5))

I tried to use anchorPoint but I can't scceed.

//: Playground - noun: a place where people can play

import UIKit

let view = UIView(frame: CGRectMake(0, 0, 200, 150))

let layer = CAShapeLayer()
let triangle = UIBezierPath()
triangle.moveToPoint   (CGPointMake( 50, 150))
triangle.addLineToPoint(CGPointMake(100,  50))
triangle.addLineToPoint(CGPointMake(150, 150))
triangle.closePath()
layer.path = triangle.CGPath
layer.strokeColor = UIColor.blueColor().CGColor
layer.lineWidth = 3.0
view.layer.addSublayer(layer)

view

layer.setAffineTransform(CGAffineTransformMakeScale(1.0, 0.5))

view

Anish gave me a advice but doesn't work well:

layer.setAffineTransform(CGAffineTransformMakeScale(2.0, 0.5))

enter image description here


Solution

  • Transforms operate around the layer's anchorPoint, which by default is at the center of the layer. Thus, you shrink by collapsing inwards, not by collapsing downwards.

    If you want to shrink downward, you will need to scale down and change the view's position (or use a translate transform in addition to your scale transform), or change the layer's anchorPoint before performing the transform.

    Another serious problem with your code is that your layer has no assigned size. This causes the results of your transform to be very misleading.

    I ran this version of your code and got exactly the results you are asking for. I have put a star next to the key lines that I added. (Note that this is Swift 3; you really need to step up to the plate and update here.)

    let view = UIView(frame:CGRect(x: 0, y: 0, width: 200, height: 150))
    let layer = CAShapeLayer()
    layer.frame = view.layer.bounds // *
    let triangle = UIBezierPath()
    triangle.move(to: CGPoint(x: 50, y: 150))
    triangle.addLine(to: CGPoint(x: 100, y: 50))
    triangle.addLine(to: CGPoint(x: 150, y: 150))
    triangle.close()
    layer.path = triangle.cgPath
    layer.strokeColor = UIColor.blue.cgColor
    layer.lineWidth = 3
    view.layer.addSublayer(layer)
    view
    layer.anchorPoint = CGPoint(x: 0.5, y: 0) // *
    layer.setAffineTransform(CGAffineTransform(scaleX: 1, y: 0.5))
    view
    

    Before:

    enter image description here

    After:

    enter image description here