Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scaling by transform does not work in UIView

In the following program, no matter what value I put in the argument of CGAffineTransform(scaleX:y:), I get the same drawing result.

Why is that?

import UIKit

class ViewController: UIViewController {
  
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    self.view.backgroundColor = .gray
  }

  override func viewWillAppear(_ animated: Bool) {
    let scalingView = ScalingView(frame: self.view.bounds)
    self.view.addSubview(scalingView)
  }
}
import UIKit

class ScalingView: UIView {
  let subview: UIView!
  
  override init(frame: CGRect) {
    subview = UIView()
    super.init(frame: frame)
    addSubview(subview)
  }
  
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  override func layoutSubviews() {
    subview.backgroundColor = .white
    let subviewSize = 100
    subview.frame.size = CGSize(width: subviewSize, height: subviewSize)
    subview.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
    subview.transform = CGAffineTransform(scaleX: 1, y: 1)
  }
}

subview.transform = CGAffineTransform(scaleX: 1, y: 1)

scaleX: 1, y: 1


subview.transform = CGAffineTransform(scaleX: 2, y: 2)

scaleX: 2, y: 2


subview.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)

scaleX: 0.5, y: 0.5


https://github.com/ll3Ynxnj/Sample-Swift-ViewScaling.git

like image 380
Kentaro Kawai Avatar asked Oct 16 '25 20:10

Kentaro Kawai


1 Answers

The issue is that every time you execute subview.transform, the layoutSubviews function also gets called, and the subview frame changes too. Without animation or delay, it actually does transform then back to the original frame. You can put some animate to check:

UIView.animate(withDuration: 1) {
    self.subview.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}

To avoid it, you have to move the setup size and frame to init so it will get called once. Then transform from outside, maybe from ViewController:

class ScalingView: UIView {
    override init(frame: CGRect) {
        ...
        let subviewSize = 100
        subview.frame.size = CGSize(width: subviewSize, height: subviewSize)
        subview.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
    }

    func scaleSubView(_ scale: CGFloat = 1.5) {
        UIView.animate(withDuration: 0.3) {
            self.subview.transform = CGAffineTransform(scaleX: scale, y: scale)
        }
    }
}
override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    scalingView.scaleSubView()
}

Notice: @matt and @HangarRash advice is helpful, you should follow it.

like image 172
sonle Avatar answered Oct 19 '25 14:10

sonle