David
David

Reputation: 447

Quality of scaled-down UILabels

I'm using Swift 3 to create an iOS interface where some UIViews containing (amongst other things) UILabels are scaled up and down based on where they're being positioned on the screen. My first approach was to create and populate the views at a comfortably large size (say 100x100) and then scale them as needed using CGAffineTransform(scaleX:y:), however I've noticed that the downscaling of the text in the labels isn't graceful at all, and the text becomes pixelated and close to unreadable at small scales. As a comparison (see example below), changing the font size directly gives much better results, however the structure within my views is somewhat complex and having to redraw everything based on some size factor would be a hassle. Is there a better and smoother way to approach this problem?

Here's an example project I've created to illustrate the problem, as well as the output in the simulator (same as on the iPhone itself), downscaled views are on the left (red) and changed font sizes are the right (green).

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        for i in 1...10 {
            let f = CGFloat(1.0) / CGFloat(i)
            let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 50))
            view1.backgroundColor = UIColor.red
            let label1 = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 50))
            label1.text = "\(100 / i)%"
            label1.font = UIFont(name: "Verdana", size: 24.0)
            label1.textAlignment = .right
            view1.addSubview(label1)
            view1.transform = CGAffineTransform(scaleX: f, y: f)
            view1.center = CGPoint(x: 160 - 75.0 * f, y: CGFloat(60 * i) + 25.0 * f)
            self.view.addSubview(view1)

            let view2 = UIView(frame: CGRect(x: CGFloat(170), y: CGFloat(60 * i), width: 150 * f, height: 50 * f))
            view2.backgroundColor = UIColor.green
            let label2 = UILabel(frame: CGRect(x: 0, y: 0, width: 150 * f, height: 50 * f))
            label2.text = "\(100 / i)%"
            label2.font = UIFont(name: "Verdana", size: 24.0 * f)
            view2.addSubview(label2)
            self.view.addSubview(view2)

        }

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

downscaling the view vs. changing the font size

Upvotes: 0

Views: 197

Answers (1)

DonMag
DonMag

Reputation: 77672

This might be an answer - but not really suitable for a comment, so...

Give this a try - it creates a 3rd "column" of yellow-background views, using .adjustsFontSizeToFitWidth. The font size will auto-adjust based on the size of the views that contain the labels.

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    for i in 1...10 {
        let f = CGFloat(1.0) / CGFloat(i)
        let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 150, height: 50))
        view1.backgroundColor = UIColor.red
        let label1 = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 50))
        label1.text = "\(100 / i)%"
        label1.font = UIFont(name: "Verdana", size: 24.0)
        label1.textAlignment = .right
        view1.addSubview(label1)
        view1.transform = CGAffineTransform(scaleX: f, y: f)
        view1.center = CGPoint(x: 160 - 75.0 * f, y: CGFloat(60 * i) + 25.0 * f)
        self.view.addSubview(view1)

        let view2 = UIView(frame: CGRect(x: CGFloat(170), y: CGFloat(60 * i), width: 150 * f, height: 50 * f))
        view2.backgroundColor = UIColor.green
        let label2 = UILabel(frame: CGRect(x: 0, y: 0, width: 150 * f, height: 50 * f))
        label2.text = "\(100 / i)%"
        label2.font = UIFont(name: "Verdana", size: 24.0 * f)
        view2.addSubview(label2)
        self.view.addSubview(view2)

        let view3 = UIView(frame: CGRect(x: CGFloat(270), y: CGFloat(60 * i), width: 150 * f, height: 50 * f))
        view3.backgroundColor = UIColor.yellow
        let label3 = UILabel(frame: view3.bounds)
        label3.text = "\(100 / i)%"
        label3.font = UIFont(name: "Verdana", size: 24.0)
        label3.adjustsFontSizeToFitWidth = true
        label3.minimumScaleFactor = 0.05
        label3.numberOfLines = 0
        // we want the label to resize with the view, if the view frame changes
        label3.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view3.autoresizesSubviews = true
        view3.addSubview(label3)
        self.view.addSubview(view3)

    }
}

Upvotes: 1

Related Questions