[cocoa] 코코아 : 프레임과 경계의 차이점은 무엇입니까?

UIView와 그 서브 클래스는 모든 속성을 가지고 framebounds. 차이점이 뭐야?



답변

경계 의 AN 의 UIView는 은 IS 직사각형 자체 좌표계 (0,0)에 대해, 위치 (x, y) 및 크기 (폭, 높이)로 표현.

프레임 의 AN 의 UIView는 은 IS 사각형 이 포함 된 수퍼 상대 위치 (x, y)의 크기 (폭, 높이)로 표현.

따라서 슈퍼 뷰의 25,25 (x, y)에 100×100 (너비 x 높이) 크기의 뷰가 있다고 가정하십시오. 다음 코드는이 뷰의 경계와 프레임을 인쇄합니다.

// This method is in the view controller of the superview
- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"bounds.origin.x: %f", label.bounds.origin.x);
    NSLog(@"bounds.origin.y: %f", label.bounds.origin.y);
    NSLog(@"bounds.size.width: %f", label.bounds.size.width);
    NSLog(@"bounds.size.height: %f", label.bounds.size.height);

    NSLog(@"frame.origin.x: %f", label.frame.origin.x);
    NSLog(@"frame.origin.y: %f", label.frame.origin.y);
    NSLog(@"frame.size.width: %f", label.frame.size.width);
    NSLog(@"frame.size.height: %f", label.frame.size.height);
}

이 코드의 출력은 다음과 같습니다.

bounds.origin.x: 0
bounds.origin.y: 0
bounds.size.width: 100
bounds.size.height: 100

frame.origin.x: 25
frame.origin.y: 25
frame.size.width: 100
frame.size.height: 100

따라서 두 경우 모두 경계 또는 프레임을 보든 관계없이 뷰의 너비와 높이가 동일하다는 것을 알 수 있습니다. 다른 점은 뷰의 x, y 위치입니다. 경계의 경우 이러한 좌표는 뷰 자체에 상대적이므로 x 및 y 좌표는 0,0입니다. 그러나 프레임 x 및 y 좌표는 상위 뷰 내에서 뷰의 위치를 ​​기준으로합니다 (이전에는 25,25에 있음).

도있다 훌륭한 프리젠 테이션 UIViews을 다룹니다. 프레임과 경계의 차이를 설명 할뿐만 아니라 시각적 인 예를 보여주는 슬라이드 1-20을 참조하십시오.


답변

짧은 답변

프레임 = 부모 뷰의 좌표계를 사용하는 뷰의 위치 및 크기

  • 중요 : 뷰를 부모에 배치

경계 = 자체 좌표계를 사용하여 뷰의 위치 및 크기

  • 중요 :보기의 컨텐츠 또는 하위보기를 자체 내에 배치

자세한 답변

프레임을 기억할 수 있도록 벽에 액자가 있다고 생각 합니다. 액자는보기의 경계와 같습니다. 벽에 원하는 곳 어디든 사진을 걸 수 있습니다. 같은 방식으로 부모 뷰 내부에 원하는 위치에 뷰를 넣을 수도 있습니다 (슈퍼 뷰라고도 함). 부모 뷰는 벽과 같습니다. iOS에서 좌표계의 원점은 왼쪽 상단입니다. 뷰 프레임의 xy 좌표를 (0, 0)으로 설정하여 슈퍼 뷰의 원점을 볼 수 있습니다. 이는 벽의 가장 왼쪽 상단에 사진을 걸어 놓는 것과 같습니다. 오른쪽으로 이동하려면 x를 높이고 아래로 이동하면 y가 증가합니다.

내가 바운드를 기억하는 것을 돕기 위해 , 나는 때때로 농구가 바운드에서 넘어지는 농구 코트를 생각 합니다 . 당신은 농구 코트 전체에 공을 드리블하지만, 법원 자체가 어디에 있는지는 실제로 신경 쓰지 않습니다. 체육관에있을 수도 있고, 고등학교 외부에 있거나 집 앞에있을 수도 있습니다. 중요하지 않습니다. 당신은 단지 농구를 원합니다. 같은 방식으로 뷰 경계의 좌표계는 뷰 자체에만 관심이 있습니다. 상위 뷰에서 뷰의 위치에 대해서는 아무것도 모릅니다. 경계의 원점 (기본적으로 (0, 0))은 뷰의 왼쪽 상단입니다. 이 견해에 대한 모든 견해는이 점과 관련하여 제시됩니다. 농구를 코트의 왼쪽 앞쪽 모서리로 가져가는 것과 같습니다.

이제 프레임과 경계를 비교하려고 할 때 혼란이 생깁니다. 그러나 실제로 처음에는 나쁘지 않습니다. 이해를 돕기 위해 그림을 사용합시다.

프레임 대 바운드

왼쪽의 첫 번째 그림에는 부모보기의 왼쪽 상단에있는보기가 있습니다. 노란색 사각형은보기의 프레임을 나타냅니다. 오른쪽에 우리는 다시보기를 볼 수 있지만 이번에는 부모보기가 표시되지 않습니다. 경계가 부모 뷰에 대해 알지 못하기 때문입니다. 녹색 사각형은 뷰의 경계를 나타냅니다. 두 이미지 의 빨간색 점 은 프레임 의 원점 을 나타냅니다 .

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds
    origin = (0, 0)
    width = 80
    height = 130

여기에 이미지 설명을 입력하십시오

따라서 그림과 프레임과 경계는 동일합니다. 그것들이 다른 예를 보자.

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds
    origin = (0, 0)
    width = 80
    height = 130

여기에 이미지 설명을 입력하십시오

따라서 프레임의 xy 좌표를 변경하면 부모 뷰에서 프레임이 이동한다는 것을 알 수 있습니다. 그러나 뷰 자체의 내용은 여전히 ​​똑같이 보입니다. 한계는 다른 것이 무엇인지 전혀 모른다.

지금까지 프레임과 경계의 너비와 높이는 정확히 동일했습니다. 그러나 항상 그런 것은 아닙니다. 뷰를 시계 방향으로 20도 회전하면 어떻게되는지보십시오. (회전은 변환을 사용하여 수행됩니다. 자세한 내용은 설명서 와 이러한 보기레이어 예제 를 참조하십시오.)

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds
    origin = (0, 0)
    width = 80
    height = 130

여기에 이미지 설명을 입력하십시오

경계가 여전히 같다는 것을 알 수 있습니다. 그들은 여전히 ​​어떤 일이 일어 났는지 모른다! 그러나 프레임 값이 모두 변경되었습니다.

이제 프레임과 경계의 차이를 보는 것이 조금 더 쉽습니다. 그렇지 않습니까? 아마도 프레임과 경계를 이해하지 못하는 기사 는 뷰 프레임을 다음과 같이 정의합니다.

… 부모 좌표계와 관련하여 해당 뷰에 적용된 모든 변형을 포함하여 해당 뷰의 가장 작은 경계 상자입니다.

뷰를 변환하면 프레임이 정의되지 않습니다. 실제로 위의 이미지에서 회전 된 녹색 경계 주위에 그린 노란색 프레임은 실제로 존재하지 않습니다. 즉, 회전, 크기 조정 또는 다른 변형을 수행하는 경우 더 이상 프레임 값을 사용하지 않아야합니다. 그래도 범위 값을 사용할 수 있습니다. Apple 문서는 경고합니다.

중요 사항 : 보기의 transform특성에 ID 변환이 포함되어 있지 않으면 해당보기의 프레임이 정의되지 않아 자동 크기 조정 동작의 결과도 나타납니다.

자동 크기 조정에 대해서는 오히려 불행한 일이지만 … 할 수있는 일이 있습니다.

Apple 문서는 다음과 같이 말합니다.

transform뷰 의 속성을 수정할 때 뷰의 중심점을 기준으로 모든 변형이 수행됩니다.

따라서 변환이 완료된 후 부모에서 뷰를 이동해야하는 경우 view.center좌표 를 변경하여 볼 수 있습니다 . 마찬가지로 frame, center부모 뷰의 좌표 시스템을 사용합니다.

자, 회전을 없애고 경계에 집중합시다. 지금까지 경계 원점은 항상 (0, 0)에 머물 렀습니다. 하지만 꼭 그럴 필요는 없습니다. 뷰에 큰 서브 뷰가 너무 커서 한 번에 모두 표시 할 수 없으면 어떻게됩니까? 우리는 그것을 UIImageView큰 이미지로 만들 것 입니다. 여기 위에서 다시 두 번째 그림이 있지만 이번에는 뷰 하위 뷰의 전체 내용이 어떻게 표시되는지 확인할 수 있습니다.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds
    origin = (0, 0)
    width = 80
    height = 130

여기에 이미지 설명을 입력하십시오

이미지의 왼쪽 위 모서리 만 뷰의 경계 안에 들어갈 수 있습니다. 이제 경계의 원점 좌표를 변경하면 어떻게되는지보십시오.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds
    origin = (280, 70)
    width = 80
    height = 130

여기에 이미지 설명을 입력하십시오

수퍼 뷰에서 프레임이 이동하지 않았지만 경계 사각형의 원점이 뷰의 다른 부분에서 시작하기 때문에 프레임 내부의 내용이 변경되었습니다. 이것은 a의 기본 개념 UIScrollView이며 하위 클래스입니다 (예 : a UITableView). 자세한 설명은 UIScrollView 이해를 참조하십시오 .

프레임 사용시기 및 경계 사용시기

frame상위 뷰에서 뷰의 위치를 ​​관련시키기 때문에 너비를 변경하거나 뷰와 상위 뷰의 상단 사이의 거리를 찾는 등 외부 변경을 할 때 사용합니다 .

뷰 내에서 사물을 그리거나 하위 뷰를 배열하는 것과 같이 안쪽으로 변경 하는 bounds경우를 사용하십시오 . 또한 일부 transfomation을 수행 한 경우 경계를 사용하여 뷰의 크기를 가져옵니다.

추가 연구를위한 기사 :

애플 문서

관련 StackOverflow 질문

기타 자료

자신을 연습

위의 기사를 읽는 것 외에도 테스트 앱을 만드는 데 많은 도움이됩니다. 비슷한 것을 시도하고 싶을 수도 있습니다. ( 이 비디오 과정 에서 아이디어를 얻었 지만 불행히도 무료는 아닙니다.)

여기에 이미지 설명을 입력하십시오

다음은 참조 용 코드입니다.

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var myView: UIView!

    // Labels
    @IBOutlet weak var frameX: UILabel!
    @IBOutlet weak var frameY: UILabel!
    @IBOutlet weak var frameWidth: UILabel!
    @IBOutlet weak var frameHeight: UILabel!
    @IBOutlet weak var boundsX: UILabel!
    @IBOutlet weak var boundsY: UILabel!
    @IBOutlet weak var boundsWidth: UILabel!
    @IBOutlet weak var boundsHeight: UILabel!
    @IBOutlet weak var centerX: UILabel!
    @IBOutlet weak var centerY: UILabel!
    @IBOutlet weak var rotation: UILabel!

    // Sliders
    @IBOutlet weak var frameXSlider: UISlider!
    @IBOutlet weak var frameYSlider: UISlider!
    @IBOutlet weak var frameWidthSlider: UISlider!
    @IBOutlet weak var frameHeightSlider: UISlider!
    @IBOutlet weak var boundsXSlider: UISlider!
    @IBOutlet weak var boundsYSlider: UISlider!
    @IBOutlet weak var boundsWidthSlider: UISlider!
    @IBOutlet weak var boundsHeightSlider: UISlider!
    @IBOutlet weak var centerXSlider: UISlider!
    @IBOutlet weak var centerYSlider: UISlider!
    @IBOutlet weak var rotationSlider: UISlider!

    // Slider actions
    @IBAction func frameXSliderChanged(sender: AnyObject) {
        myView.frame.origin.x = CGFloat(frameXSlider.value)
        updateLabels()
    }
    @IBAction func frameYSliderChanged(sender: AnyObject) {
        myView.frame.origin.y = CGFloat(frameYSlider.value)
        updateLabels()
    }
    @IBAction func frameWidthSliderChanged(sender: AnyObject) {
        myView.frame.size.width = CGFloat(frameWidthSlider.value)
        updateLabels()
    }
    @IBAction func frameHeightSliderChanged(sender: AnyObject) {
        myView.frame.size.height = CGFloat(frameHeightSlider.value)
        updateLabels()
    }
    @IBAction func boundsXSliderChanged(sender: AnyObject) {
        myView.bounds.origin.x = CGFloat(boundsXSlider.value)
        updateLabels()
    }
    @IBAction func boundsYSliderChanged(sender: AnyObject) {
        myView.bounds.origin.y = CGFloat(boundsYSlider.value)
        updateLabels()
    }
    @IBAction func boundsWidthSliderChanged(sender: AnyObject) {
        myView.bounds.size.width = CGFloat(boundsWidthSlider.value)
        updateLabels()
    }
    @IBAction func boundsHeightSliderChanged(sender: AnyObject) {
        myView.bounds.size.height = CGFloat(boundsHeightSlider.value)
        updateLabels()
    }
    @IBAction func centerXSliderChanged(sender: AnyObject) {
        myView.center.x = CGFloat(centerXSlider.value)
        updateLabels()
    }
    @IBAction func centerYSliderChanged(sender: AnyObject) {
        myView.center.y = CGFloat(centerYSlider.value)
        updateLabels()
    }
    @IBAction func rotationSliderChanged(sender: AnyObject) {
        let rotation = CGAffineTransform(rotationAngle: CGFloat(rotationSlider.value))
        myView.transform = rotation
        updateLabels()
    }

    private func updateLabels() {

        frameX.text = "frame x = \(Int(myView.frame.origin.x))"
        frameY.text = "frame y = \(Int(myView.frame.origin.y))"
        frameWidth.text = "frame width = \(Int(myView.frame.width))"
        frameHeight.text = "frame height = \(Int(myView.frame.height))"
        boundsX.text = "bounds x = \(Int(myView.bounds.origin.x))"
        boundsY.text = "bounds y = \(Int(myView.bounds.origin.y))"
        boundsWidth.text = "bounds width = \(Int(myView.bounds.width))"
        boundsHeight.text = "bounds height = \(Int(myView.bounds.height))"
        centerX.text = "center x = \(Int(myView.center.x))"
        centerY.text = "center y = \(Int(myView.center.y))"
        rotation.text = "rotation = \((rotationSlider.value))"

    }

}


답변

아래 코드를 실행하십시오

- (void)viewDidLoad {
    [super viewDidLoad];
    UIWindow *w = [[UIApplication sharedApplication] keyWindow];
    UIView *v = [w.subviews objectAtIndex:0];

    NSLog(@"%@", NSStringFromCGRect(v.frame));
    NSLog(@"%@", NSStringFromCGRect(v.bounds));
}

이 코드의 출력은 다음과 같습니다.

케이스 장치 방향이 세로

{{0, 0}, {768, 1024}}
{{0, 0}, {768, 1024}}

케이스 장치 방향은 가로

{{0, 0}, {768, 1024}}
{{0, 0}, {1024, 768}}

분명히, 당신은 프레임과 경계의 차이를 볼 수 있습니다


답변

프레임 과의 UIView를 정의하는 직사각형 의 수퍼 대하여 .

RECT 경계 되도록 정의 값의 범위 NSView의 좌표계입니다.

즉,이 사각형의 모든 것은 실제로 UIView에 표시됩니다.


답변

frame 은 수퍼 뷰의 좌표계에서 뷰의 원점 (왼쪽 상단)과 뷰의 크기입니다. 이것은 프레임 원점, 경계를 변경하여 수퍼 뷰에서 뷰를 변환한다는 것을 의미 합니다 는 그 크기와 원점입니다 자체 좌표계이므로 기본적으로 경계 원점은 (0,0)입니다.

대부분의 경우 프레임과 경계가 합동이지만 프레임 ((140,65), (200,250)) 및 경계 ((0,0), (200,250))의 뷰가 있고 뷰가 기울어 진 경우 오른쪽 하단에 서 있도록 경계는 여전히 ((0,0), (200,250))이지만 프레임은 아닙니다.

여기에 이미지 설명을 입력하십시오

프레임은 뷰를 캡슐화 / 서라운드하는 가장 작은 사각형이므로 사진과 같이 프레임은 ((140,65), (320,320)이됩니다.

또 다른 차이점은 예를 들어 범위가 ((0,0), (200,200)) 인 superView가 있고이 superView에 프레임이 ((20,20), (100,100)) 인 subView가 있고 superView 범위를 변경 한 경우 ((20,20), (200,200))이면 subView 프레임은 여전히 ​​((20,20), (100,100))이지만 슈퍼 뷰 좌표계가 (20, 20).

나는 이것이 누군가를 돕기를 바랍니다.


답변

SuperView를 기준으로 프레임을 구성하고 NSView를 기준으로 경계를 설정합니다.

예 : X = 40, Y = 60. 또한 3 개의 뷰가 포함되어 있습니다.이 다이어그램은 명확한 아이디어를 보여줍니다.

틀

범위


답변

5 센트를 추가하겠습니다.

프레임 은 뷰의 상위 뷰에서 상위 뷰 내에 배치하는 데 사용됩니다.

바운드 는 뷰 자체에서 자체 컨텐츠를 배치하기 위해 사용됩니다 (스크롤 뷰가 스크롤하는 동안). clipsToBounds 도 참조하십시오 . 경계를 사용하여 뷰의 내용을 확대 / 축소 할 수도 있습니다.

유추 :
프레임 ~ TV 화면
경계 ~ 카메라 (확대, 이동, 회전)