달력

12

« 2019/12 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

'2019/12'에 해당되는 글 1

  1. 2019.12.07 UIView bounds vs frame 1
2019. 12. 7. 17:12

UIView bounds vs frame iOS Development/ETC2019. 12. 7. 17:12

1. Intro

: UIView의 bounds와 frame의 차이가 무엇이냐고 하면, 좌표계(Coordinate System)의 차이를 이야기하며 설명하는 분들이 많다. 그렇다면 좌표계가 다르면 어떤 차이가 있을까? origin만 다를까? 이번 포스트에서는 이에 대해 이야기를 해보고자 한다.

 

 

2. Apple 문서에 소개된 bounds과 frame

 

* bounds - Apple 문서 링크

: 본인 관점의 좌표계(Coordinate System) 기준으로 View의 크기와 위치를 나타낸다. default bounds는 origin 값이 (0, 0)이고 size 값은 frame의 것과 같다. Rectangle 일부의 size를 변경하면, View의 center를 기준으로 변경된다. Rectangle의 size가 변경되면, frame의 size도 변경된다. (이하 생략)

 

* frame - Apple 문서 링크

: 부모 뷰(Superview) 관점의 좌표계 기준으로 View의 크기와 위치를 나타낸다. 그 외에는 bounds에서 Rectangle의 size가 변경될때 frame의 size을 바꿧던 것과 같이, bounds의 size을 바꾼다. 대부분의 특성이 bounds와 비슷한데, 조금 특이한 경고문이 Apple 문서에 다음과 같이 적혀있는데...

 

Warning

: view의 transform이 identity(CGAffineTransform.identity)가 아니면, frame의 값은 정의되지 않는다. 따라서 이때의 frame 값은 무시하는게 좋다(should).

 

 frame의 값이 도대체 어떻게 되길래, 정의되지 않고 무시하는게 좋다고 적혀있는 것일까? 궁금하다.

 

 

3. view에 transform을 해보면서 비교하기

: 직사각형의 frame이 (x: 60, y: 60, width: 40, height: 100)인 초록색(UIColor.green, alpha: 0.7) view를 추가해보면 다음과 같다.

 

그림1. 직사각형 View를 하나 추가하였음.

 

이 상황에서, 직사각형의 frame이 (x: 60, y: 60, width: 40, height: 100)인 파란색(UIColor.blue, alpha: 0.7) view를 추가하고, 파란색 View의 transform을 CGFloat.pi * 0.25만큼 회전(rotation)시키면 다음과 같다.

 

1
blueView.transform = CGAffineTransform(rotationAngle: .pi * 0.25)
cs

 

그림2. rotation시킨 파란색 view 추가

 

그림 2의 초록색 view와 파란색 view의 frame과 bounds를 출력시켜 보았다.

 

* 초록색 view와 파란색 view의 frame

초록색 view의 frame : (x: 60, y: 60, width: 40, height: 100)

파란색 view의 frame : (x: 30.502525316941686, y: 60.50252531694167, width: 98.99494936611664, height: 98.99494936611666)

 

파란색 view의 frame 값이 다르다. origin(x, y)은 물론이고, size(width, height)도 초록색 view와 많이 다르다.

 

 

* 초록색 view와 파란색 view의 bounds

초록색 view의 bounds : (x: 0, y: 0, width: 40, height: 100)

파란색 view의 bounds : (x: 0, y: 0, width: 40, height: 100)

 

이번에는 두 view의 bounds가 동일하다. 사실 생각해보면, bounds가 본인 관점의 좌표계 기준으로 보기 때문에... 회전 여부와 관계없이 같아야 하는게 당연해 보인다.

 

 

 

초록색 view와 파란색 view의 frame이 다른 것을 보고, 파란색 view의 frame가 어떤 값인지 궁금하였다. 그래서 파란색 view의 frame과 동일한 다른 view를 그려보았다.

 

* 파란색 view의 frame과 동일한 view

파란색 view의 frame과 동일한(x: 30.502525316941686, y: 60.50252531694167, width: 98.99494936611664, height: 98.99494936611666) 회색(UIColor.gray, alpha: 0.7) view를 그려보면 다음과 같다.

 

그림3. 파란색 view의 frame이 그리는 영역

 

회색 view가 그려진 영역을 보고, frame을 다음과 같이 추론해보았다...

 

"frame은, transform을 한 다음의 (x: minX, y: minY, width: maxX - minX, height: maxY - minY)으로 추정된다."

 

 

* transform된 view에 CGAffineTransform.identity로 transform해보기

파란색 view는 이미 transform이 되었다. 이 상태에서 transform에 CGAffineTransform.identity를 넣어주면 어떻게 될까? 그림2의 파란색 view의 transform에 CGAffineTransform.identity을 넣어주면 다음과 같다.

 

그림4. transform된 view에 .identity로 transform하기

 

 아무런 transform하기 전인, 초록색 view를 완전히 덮었다. CGAffineTransform.identity는 CGAffineTransform(rotationAngle: .pi * 0.25)의 Inverse Matrix가 아니다. 여기서 추론해보면...

 

"transform되기 전 view의 frame을 알 수 있도록, vector 같은게 저장되어 있을 것."

 

 

4. Conclusion

: view에 transform을 해보며 bounds와 frame의 특징과 관계를 추론해볼 수 있었다. 정리해보면 다음과 같다.

 

1. CGAffineTransform.identity으로 transform된 view의 frame을 알 수 있도록,

   vector 같은 것이 저장되어 있을 것.

2. bounds는 아마도, CGAffineTransform.identity으로 transform된 frame의 size를 출력해줄듯.

3. 우리가 접근하는 frame은 transform한 다음의

   (x: minX, y: minY, width: maxX - minX, height: maxY - minY)일 듯.

 

어디까지나 나의 추론이므로, 어쩌면 잘못된 부분이 있을지도 모른다. 그러니까 UIKit, CoreGraphic 코드좀 보여주세요 애플님.

 

 

여담이지만, view의 transform을 적용할 때... 조심할 점이 있다. CGAffineTransform문서를 보면, 3x3 matrix가 있는데... 여기에 UIView의 좌표를 이용하여 계산을 하면 무엇인가 계산결과가 이상하다는 것을 알 수 있다. Quartz 2D Programming Guide를 보면 그 이유를 알 수 있는데, Quartz가 CGAffineTransform의 matrix를 이용해서 계산을 한다. 하지만 Quartz와 UIKit은 Coordinate System이 안맞으니, 계산결과가 이상할 수 밖에.

 

아 그리고, 이런 고민을 할 수 있도록 소재를 던져주신 Sadarm님 감사합니다.

:
Posted by syjdev