UIView
와 그 서브 클래스는 모든 속성을 가지고 frame
와 bounds
. 차이점이 뭐야?
UIView
와 그 서브 클래스는 모든 속성을 가지고 frame
와 bounds
. 차이점이 뭐야?
답변:
경계 의 AN 의 UIView는 은 IS 직사각형 자체 좌표계 (0,0)에 대해, 위치 (x, y) 및 크기 (폭, 높이)로 표현.
프레임 의 AN 의 UIView는 은 IS 사각형 이 포함 된 수퍼 상대 위치 (x, y)의 크기 (폭, 높이)로 표현.
따라서 슈퍼 뷰의 25,25 (x, y)에 100x100 (너비 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 변환이 포함되어 있지 않으면 해당보기의 프레임이 정의되지 않아 자동 크기 조정 동작의 결과도 나타납니다.
자동 크기 조정에 대해서는 오히려 불행한 일이지만 ... 할 수있는 일이 있습니다.
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))"
}
}
bounds
대 frame
뷰의.
아래 코드를 실행하십시오
- (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}}
분명히, 당신은 프레임과 경계의 차이를 볼 수 있습니다
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).
나는 이것이 누군가를 돕기를 바랍니다.
subView
frame은 그것과 관련이 superView
있습니다. superView
범위를 변경하면 subView
원점이 그것과 일치 하지 않습니다 superView
.
5 센트를 추가하겠습니다.
프레임 은 뷰의 상위 뷰에서 상위 뷰 내에 배치하는 데 사용됩니다.
바운드 는 뷰 자체에서 자체 컨텐츠를 배치하기 위해 사용됩니다 (스크롤 뷰가 스크롤하는 동안). clipsToBounds 도 참조하십시오 . 경계를 사용하여 뷰의 내용을 확대 / 축소 할 수도 있습니다.
유추 :
프레임 ~ TV 화면
경계 ~ 카메라 (확대, 이동, 회전)
위의 답변은 경계와 프레임의 차이점을 잘 설명했습니다.
경계 : 자체 좌표계에 따른 뷰 크기 및 위치.
프레임 : SuperView를 기준으로 한 뷰 크기 및 위치입니다.
그러면 경계의 경우 X, Y가 항상 "0"이된다는 혼동이 있습니다. 사실이 아닙니다 . UIScrollView 및 UICollectionView에서도 이해할 수 있습니다.
경계의 x, y가 0이 아닌
경우 UIScrollView가 있다고 가정합니다. 페이지 매김을 구현했습니다. UIScrollView는 3 페이지이며 ContentSize의 너비는 화면 너비의 3 배입니다 (ScreenWidth가 320이라고 가정). 높이는 일정합니다 (200으로 가정).
scrollView.contentSize = CGSize(x:320*3, y : 200)
세 개의 UIImageView를 subView로 추가하고 프레임 의 x 값을 자세히 살펴보십시오.
let imageView0 = UIImageView.init(frame: CGRect(x:0, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView1 : UIImageView.init( frame: CGRect(x:320, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
let imageView2 : UIImageView.init(frame: CGRect(x:640, y: 0 , width : scrollView.frame.size.width, height : scrollView.frame.size.height))
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
scrollView.addSubview(imageView0)
페이지 0 : ScrollView가 0 페이지 인 경우 경계는 (x : 0, y : 0, 너비 : 320, 높이 : 200)입니다.
1 페이지 : 스크롤하여 1 페이지로 이동합니다.
이제 경계는 (x : 320, y : 0, 너비 : 320, 높이 : 200)
입니다. 자체 좌표계와 관련하여 말했음을 기억하십시오. 이제 ScrollView의 "Visible Part"는 320에서 "x"를 갖습니다. imageView1의 프레임을보십시오.
UICollectionView의 경우에도 동일합니다. collectionView를 보는 가장 쉬운 방법은 그것을 스크롤하고 경계를 인쇄 / 기록하는 것입니다.
프레임 대 바운드
프레임 = 부모 뷰의 좌표계를 사용하는 뷰의 위치 및 크기
경계 = 자체 좌표계를 사용하여 뷰의 위치 및 크기
뷰는 프레임 사각형과 경계 사각형의 두 사각형을 사용하여 크기와 위치를 추적합니다. 프레임 사각형은 슈퍼 뷰의 좌표계를 사용하여 슈퍼 뷰에서 뷰의 위치와 크기를 정의합니다. 경계 사각형은 원점 및 배율을 포함하여 뷰의 내용을 그릴 때 사용되는 내부 좌표계를 정의합니다. 그림 2-1은 프레임 사각형 (왼쪽)과 경계 사각형 (오른쪽)의 관계를 보여줍니다.”
간단히 말해서 프레임은 뷰에 대한 수퍼 뷰의 아이디어이고 범위는 뷰 자체의 아이디어입니다. 각 뷰마다 하나씩 여러 좌표계를 갖는 것은 뷰 계층의 일부입니다.