๋งจ๋‚  ํ—ท๊ฐˆ๋ฆฌ๋Š” ์ด๊ฒƒ. ์˜ค๋Š˜์€ ๋ฝ‘์•„๋ฒ„๋ฆฌ๊ฒ ๋‹ค.

Frame

Super view์˜ ์ขŒํ‘œ๊ณ„๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ–ˆ์„ ๋•Œ ๋ณธ์ธ์˜ ์ขŒํ‘œ๊ณ„๋ฅผ ๋งํ•œ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์œ„์น˜๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ธฐ์ค€ ์ขŒํ‘œ๊ณ„๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. iPhone์˜ ๊ฒฝ์šฐ ์ขŒ์ƒ๋‹จ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ x์ถ•์€ ์˜ค๋ฅธ์ชฝ, y์ถ•์€ ์•„๋ž˜๋กœ ๊ฐ€๋Š” ๊ธฐ๋ณธ ์ขŒํ‘œ๊ณ„๋ฅผ ๊ฐ–๋Š”๋‹ค.

์ด ๊ทผ๋ณธ ์ขŒํ‘œ๊ณ„ ์œ„์—์„œ ์šฐ๋ฆฌ๋Š” ์š”์†Œ๋“ค์„ ๋†“์•„์•ผ ํ•˜๋Š”๋ฐ, ์ด ๋•Œ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ด ๋˜๋Š” ๊ฒƒ์ด frame์ด๋‹ค. apple์€ ํŠน์ • ์š”์†Œ๋ฅผ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ๋•Œ, ํ•ด๋‹น ์š”์†Œ๋ฅผ ๋†“์„ ๊ธฐ์ค€์„ ๋‚˜์˜ ๋ถ€๋ชจ๋กœ ์žก์•˜๋‹ค. ์ฆ‰, ๋‚˜์˜ ๋ถ€๋ชจ์— ๋น„ํ•ด์„œ ๋‚˜์˜ ์œ„์น˜๊ฐ€ ์–ด๋”˜๊ฐ€?๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ. ๊ทธ๋ฆฌ๊ณ  ์ด ์ƒ๊ฐ์— ๊ฐ€์žฅ ๋งž๋Š” ์š”์†Œ๊ฐ€ frame์ด๋‹ค.

์ด๋ ‡๊ฒŒ ๋‚ด๊ฐ€ ๋†“๊ณ  ์‹ถ์€ ์š”์†Œ์˜ ์œ„์น˜๋ฅผ ํŒŒ์•…ํ•  ๋•Œ, ํ•ญ์ƒ ๋ถ€๋ชจ View์— Subview๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฌํ•œ ์‚ฌ๊ณ ๋Š” ์‚ฌ์‹ค ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.

let parentView = UIView()
let childView = UIView()
 
parentView.addSubview(childView)
childView.frame = CGRect(x: 10, y: 10, width: 20, height: 40) // ๋ถ€๋ชจ๋ทฐ ๊ธฐ์ค€์œผ๋กœ ์œ„์น˜ ์„ ์ •

Rotate

ํšŒ์ „์˜ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–จ์ง€ ๊ถ๊ธˆํ•˜์—ฌ ๋Œ๋ ค๋ณด์•˜๋‹ค.

----------
ViewA frame: (0.0, 0.0, 390.0, 844.0)
ViewA bounds: (0.0, 0.0, 390.0, 844.0)
ViewB frame: (100.0, 200.0, 200.0, 300.0)
ViewB bounds: (0.0, 0.0, 200.0, 300.0)
----------

์—ฌ๊ธฐ๊นŒ์ง€๋Š” ๋ฐฉ๊ธˆ ์ดํ•ดํ•œ ๋‚ด์šฉ๊ณผ ๊ฐ™๋‹ค.

----------
ViewA frame: (0.0, 0.0, 390.0, 844.0)
ViewA bounds: (0.0, 0.0, 390.0, 844.0)
ViewB frame: (23.22330470336314, 173.2233047033631, 353.5533905932738, 353.55339059327383)
ViewB bounds: (0.0, 0.0, 200.0, 300.0)
----------

ํšŒ์ „ํ•˜๊ฒŒ ๋˜๋‹ˆ viewB์˜ frame์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค. ์ด๋Š” ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์‚ฌ๊ฐํ˜•์„ ๋ชจ๋‘ ํฌํ•จํ•˜๋ฉด์„œ ์ตœ์†Œ์ธ ์‚ฌ๊ฐํ˜•์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด frame์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฐ์‹์œผ๋กœ ๊ฐ์‹ผ ์‚ฌ๊ฐํ˜•์ด frame์ด๋‹ค.

Bounds

์ž์‹ ๋งŒ์˜ ๊ณ ์œ ํ•œ ์ขŒํ‘œ๊ณ„

๊ทธ๋ ‡๋‹ค๋ฉด ์ € ์‹ค์ œ ์‚ฌ๊ฐํ˜•์— ๊ด€๋ จ๋œ ๊ฐ’์„ ์–ป์„ ์ˆ˜๋Š” ์—†์„๊นŒ? ๊ทธ๊ฒƒ์ด bounds์ด๋‹ค. ์„ค๋ช…์„ ๋ณด๋ฉด ์ž์‹ ๋งŒ์˜ ๊ณ ์œ ํ•œ ์ขŒํ‘œ๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ๋•Œ๋ฌธ์—, ํ˜„์žฌ ํšŒ์ „๋œ ์ƒํ™ฉ์—์„œ bounds์˜ ์ขŒํ‘œ๊ณ„๋ฅผ ๊ทธ๋ ค๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

----------
ViewA frame: (0.0, 0.0, 390.0, 844.0)
ViewA bounds: (0.0, 0.0, 390.0, 844.0)
ViewB frame: (23.22330470336314, 173.2233047033631, 353.5533905932738, 353.55339059327383)
ViewB bounds: (0.0, 0.0, 200.0, 300.0)
----------

์‹ค์ œ๋กœ ํšŒ์ „๋œ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ ๊ฐ’์„ ์ฐ์–ด๋ณด๋ฉด, ํšŒ์ „๋์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ViewB์˜ Bounds๋Š” ๋™์ผํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

Bounds๋ฅผ ๋ฐ”๊ฟ”๋ณด์ž

viewA(๋…ธ๋ž‘)์— subview๋กœ viewB(ํŒŒ๋ž‘)๊ฐ€ ๋“ค์–ด๊ฐ€ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ viewA์˜ bounds๋ฅผ ๋ฐ”๊ฟ”๋ณด๊ฒ ๋‹ค.

self.viewA.bounds.origin = CGPoint(x: 100, y: 200)

์™œ ํŒŒ๋ž€์ƒ‰ ๋ทฐ๊ฐ€ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ”์„๊นŒ? ์šฐํ•˜๋‹จ์œผ๋กœ ๊ฐ€์•ผ๋˜๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€? ๋ผ๊ณ  ์ƒ๊ฐํ•œ ์‚ฌ๋žŒ์ด ์žˆ๋‹ค๋ฉด ์ž˜์™”๋‹ค. bounds์˜ ์ด๋™์€ ์ขŒํ‘œ๊ณ„์˜ ์ด๋™์ด๋‹ค.

์ขŒํ‘œ๊ณ„๊ฐ€ (100, 200) ์›€์ง์ด๊ณ , ์‹ค์ œ ๋ณด์ด๋Š” ํ™”๋ฉด์€ ์ด ์›€์ง์ธ ์ขŒํ‘œ๊ณ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด์„œ ๋ณด์—ฌ์ง„๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€๋งŒํžˆ ์žˆ๋Š” viewB๊ฐ€ ์šฐ๋ฆฌ ๋ˆˆ์—๋Š” ์ขŒ์ƒ๋‹จ์œผ๋กœ ๊ฐ„๊ฒƒ ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ฒƒ์ด๋‹ค!!

Whole Code

import UIKit
 
class FrameBoundsViewController: UIViewController {
 
    let viewA: UIView = {
        let view = UIView()
        view.backgroundColor = .yellow
        return view
    }()
 
    let viewB: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        return view
    }()
 
    let rotateButton: UIButton = {
        let button = UIButton()
        button.setTitle("45๋„ ํšŒ์ „", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        return button
    }()
 
    let debugButton: UIButton = {
        let button = UIButton()
        button.setTitle("DEBUG", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        return button
    }()
 
    let boundsButton: UIButton = {
        let button = UIButton()
        button.setTitle("ViewA Bounds +10, +10", for: .normal)
        button.setTitleColor(UIColor.black, for: .normal)
        return button
    }()
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        self.viewA.frame = CGRect(origin: .zero, size: self.view.frame.size)
        self.viewB.frame = CGRect(origin: CGPoint(x: 100, y: 200), size: CGSize(width: 200, height: 300))
        self.rotateButton.frame = CGRect(x: 20, y: 600, width: 200, height: 40)
        self.debugButton.frame = CGRect(x: 220, y: 600, width: 200, height: 40)
        self.boundsButton.frame = CGRect(x: 20, y: 700, width: 400, height: 40)
 
        self.view.addSubview(self.viewA)
        self.view.addSubview(self.rotateButton)
        self.view.addSubview(self.debugButton)
        self.viewA.addSubview(self.viewB)
 
        self.rotateButton.addTarget(self, action: #selector(self.rotateRectangle), for: .touchUpInside)
        self.debugButton.addTarget(self, action: #selector(self.debug), for: .touchUpInside)
 
        self.viewA.bounds.origin = CGPoint(x: 100, y: 200)
    }
 
    @objc func rotateRectangle() {
        UIView.animate(withDuration: 1) {
            self.viewB.transform = CGAffineTransform(rotationAngle: .pi/4)
        }
    }
 
    @objc func debug() {
        print("----------")
        print("ViewA frame: \(self.viewA.frame)")
        print("ViewA bounds: \(self.viewA.bounds)")
        print("ViewB frame: \(self.viewB.frame)")
        print("ViewB bounds: \(self.viewB.bounds)")
        print("----------")
    }
 
}

๋งˆ๋ฌด๋ฆฌ

๊ฐ„๋‹จํ•˜๊ฒŒ frame, bounds์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜๋‹ค. bounds๋Š” ์‹ค์ œ ๋ˆˆ์— ๋ณด์ด๋Š” ์ขŒํ‘œ๊ณ„๊ฐ€ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ž„์„ ๊ธฐ์–ตํ•˜์ž. ์ขŒํ‘œ๊ณ„๊ฐ€ ์›€์ง์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ๋ˆˆ์— ๋ณด์ด๋Š” ๋…€์„์€ ์ •๋ฐ˜๋Œ€๋กœ ์›€์ง์ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ๋œ๋‹ค. ๋!

Reference