Weekoding

[Swift] UIColor/CGColor, CGSize/CGPoint/CGRect, frame/bounds 본문

공부 노트(Swift)

[Swift] UIColor/CGColor, CGSize/CGPoint/CGRect, frame/bounds

Weekoding 2023. 2. 13. 00:38

오늘은 헷갈리는 개념들을 총 정리 하는 시간을 가져보도록 할 예정이다.

한 묶음씩 포스팅 하면 찾기도 번거로울 것 같고 간단하게 정리해 보려고 한다.

주인공들은 아래와 같다.

  • UIColor / CGColor
  • CGSize / CGPoint / CGRect
  • frame / bounds

 

📂  UIColor / CGColor

background 속성이 CALayer에 속해있냐, UIView에 속해있냐에 따라 받는 값의 클래스가 다르다.

좌: UIView의 backgroundColor, 우: CALayer의 backgroundColor

일단, Layer가 해당 View에 속해 있다면, View.backgroundColor를 바꿀 때 Layer.backgroundColor자동으로 함께 바뀐다.

반대로 설정해도 마찬가지.

 

그런데 왜 CGColor / UIColor라는 개념이 나누어져 있으며, 위와 같이 같은 'backgroundColor' 속성도 받는 클래스가 다른 것일까?

UIView.backgroundColor만 바꿔 주었는데 같은 색상이 찍힌다.

 

UIColor

An object that stores color data and sometimes opacity.

: UIkit/Drawing에 속해 있으며, 색상과 투명도 데이터를 저장하는 object이다. 

UIColor provides a list of class properties that create adaptable and fixed colors such as blue, green, purple, and more. UIColor also offers properties to specify system-provided colors for UI elements such as labels, text, and buttons.

: UIColor는 적용 가능한 고정 색상 값(blue, green, purple 등등)을 만드는 class properties 목록을 제공한다.

  또한, UIColor는 UI elements(label, text, buttons 등)에 대해 system-provided color를 지정할 수 있는 properties를 제공한다. 

 

 

CGColor

A set of components that define a color, with a color space specifying how to interpret them.

: CoreGraphics에 속해 있으며,  색상을 지정하는 요소들의 집합체.(아마.. RGB, CMYK등을 의미하는 것 같다) 

CGColor is the fundamental data type used internally by Core Graphics to represent colors. 
CGColor objects, and the functions that operate on them, provide a fast and convenient way of managing and setting colors directly, especially colors that are reused (such as black for text).

: CGColor는 CoreGraphics에서 색상 표현 시 내부적으로 사용하는 기본적인 데이터 유형이다.

  CGColor객체와 그것을 통해 동작하는 함수는, 색상을 적용하고 관리하는 데에(특히 재사용 되는 컬러 - text의 black)

  빠르고 간편한 방법을 제공한다.

 

 

아! 👏  두 클래스의 가장 큰 차이점은 '어느 프레임워크에 속해 있는가' 였다.

    UIView를 상속받는 View들은 UIColor를, Core Graphics로부터 그려지는 Layer들은 CGColor를 사용하는 것이다.

    다소 생소한 CGColor는 생성이 어렵다면 UIColor의 cgColor를 이용할 수 있다.

layer.borderColor = UIColor.black.cgColor

    +) 또한, UIColoropacity값을 포함하고 있어 투명도를 조절할 수 있다.

 

 

 

📂  CGSize / CGPoint / CGRect

CG를 한 두번 보는 것이 아니니 이젠 Core Graphics라는 것을 알겠다.

Graphics와 관련하여 다양한 프로퍼티 / 메소드를 제공하다 보니 확실히 이렇게 복잡하구나..

 

CGSize

A structure that contains width and height values.

: 높이와 너비에 대한 값을 갖는 구조체.

 

 

CGPoint

A structure that contains a point in a two-dimensional coordinate system.

: 2차원 좌표계 값(x, y)을 갖는 구조체.

 

 

CGRect

A structure that contains the location and dimensions of a rectangle.

: 위치와, 직사각형의 면적에 대한 값을 갖는 구조체.

  CGRect는 CGSize(x, y)로 위치를, CGPoint(width, height)로 면적을 지정한다.

  따라서 View를 그릴 때, View.frame은 CGRect를 값으로 받는다.

In the default Core Graphics coordinate space, the origin is located in the lower-left corner of the rectangle and the rectangle extends towards the upper-right corner.
If the context has a flipped-coordinate space—often the case on iOS—the origin is in the upper-left corner and the rectangle extends towards the lower-right corner.

: 기본 Core Graphics 좌표 공간에서,

  원점은 직사각형의 왼쪽 하단 모서리를 기준으로 시작하고, 직사각형은 오른쪽 상단 모서리로 확장된다.
  만약 context에 뒤집힌 좌표 공간이 있다면(주로 iOS의 경우가 많다),

  원점은 왼쪽 상단 모서리에 있고 직사각형은 오른쪽 하단 모서리로 확장된다.(사진 참고)

https://developer.apple.com/library/archive/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html

 

 

결론적으로, CGRect / CGPoint / CGSize의 관계는 다음과 같다.

위치에 대한 값을 갖는 CGPoint,

면적에 대한 값을 갖는(높이와 너비) CGSize,

그 둘을 통해 생성되어 실체(실제 Rectangle)를 가지는 CGRect !

 

 

 

📂  frame / bounds

frame과 bounds가 가장 이해하기 어려웠다 (특히 bounds)

또한 방금 공부한 CGRect의 개념이 필요해서 CGRect에 대한 이해가 충분히 되어야 한다.

둘은 공통적으로 UIView를 상속받는다.

 

frame

The frame rectangle, which describes the view’s location and size in its superview’s coordinate system.

frame이라 불리는 직사각형은, 슈퍼뷰의 좌표계 내에서의 뷰의 위치와 크기를 그리는 직사각형이다.

 

 

bounds

The bounds rectangle, which describes the view’s location and size in its own coordinate system.

bounds라 불리는 직사각형은, 뷰 자신의 고유 좌표계 내에서 자신(뷰)의 위치와 크기를 그리는 직사각형이다.

 

나머지 개념은 차이점을 바로 비교해보면서 세부적으로 뜯어보자.

둘은 origin, size라는 공통 프로퍼티를 갖고 있다. 그러나, 기준점이 다르기 때문에 내용은 전혀 다르다.

 

 

 

🥊 frame.origin vs bounds.origin

frame은 슈퍼뷰의 좌표계를 기준으로 계산하기 때문에,

저 darkgreyView의 frame.origin은 슈퍼뷰의 왼쪽 상단에서 얼마나 떨어져있느냐가 된다.

 

bounds는 자신의 좌표계를 기준으로 계산하므로,

darkgreyView, 즉 자신의 왼쪽 상단이 bounds.origin가 된다.

그래서 처음에는 모두 (0, 0)으로 되어 있다. 값이 바뀌면 어떻게 될지는 아래에서 다시 알아보겠다.

 

 

🥊 frame.size vs bounds.size

darkGreyView의 size = width:200, height: 140일 때

일반적인 상태에서는 frame.size와 bounds.size의 차이가 느껴지지 않겠지만,

View를 약간 회전 시키면 그 차이를 이해하기 쉽다.

 

frame.sizeview를 모두 감싸는 영역의 크기를 의미하므로,

view 상태에 따라 값이 변화할 수 있다.

bounds.sizeview 자체의 영역의 크기를 의미한다.

 

 

 

🥊 frame.origin이 변화할 때 vs bounds.origin이 변화할 때

오늘 공부했던 것 중에 가장 어려운 부분이었다.

(size의 변화는 서로 의미하는 것이 다를 뿐, 단순히 의미하는 rectangle의 크기가 변화하는 것은 같다.)

 

frame.origin이 이동 할 때는, 당연히 SuperView를 기준으로 움직이게 된다.  

 

여기까진 이해가 수월했을 것이다.

이번엔 darkgreyView의 bounds.origin을 움직여 보자.(darkgreyView의 subview로 margentaView를 추가했다.)

??????

이해도 안될 뿐더러, margentaView의 이동은 margentaView의 frame.origin을 (-100, -30)으로 이동한 느낌이다.

이것을 이해하려고 노력하다가 viewPort라는 개념을 알게 되었다.

 

viewPort

: 화면에 보여지는 영역.

  화면 사이즈 보다 큰 view의 경우에는 일부만 보이는데, 그것이 viewPort 영역이다.

 

그래서 viewPort를 곁들여 다시 설명하자면..

더 여러운가,, ㅎㅎ,,,,

bounds는 View자체가 움직이는 것이 아니라 viewPort가 움직이는 것이다.

그림은 뒤의 큰 view가 움직인 것 처럼 보이지만, 화면이 (100, 30)만큼 움직였다고 생각하면 이해가 쉬울 것이다.

darkgreyView의 origin(0, 0) 자체가 (100, 30)만큼 이동해서 View를 그리는 것이니,

당연히 하위에 있는 margentaView는 따로 변한 origin 값이 없기 때문에 함께 움직이는 것처럼 보이는 것이다.

 

휴대폰 카메라를 켜서 A4 용지에 물체를 하나 두고 물체를 그 위에 둔 다음,

물체를 움직이는 것이 아니라 A4를 움직이면 물체도 당연히 함께 움직이는 것 처럼 보이는 것과 같은 원리이다.

 

그래서 scrollView를 다룰 때 bounds.origin 값을 자주 다루게 될 것이다.

scrollView 자체가 기기 화면보다 큰 content를 나타내기 위해 사용하는 것이므로,

위 viewPort 개념과 동일하게 스크롤을 한다는 개념은 bounds 값이 변화한다는 의미이기 때문이다. 

 

frame / bounds를 표로 정리한다면 다음과 같다.

  frame bounds
origin superview를 기준 자기 자신(view) 기준. 기본적으로 (0, 0)
size view를 '포함하는' 사각형의 width, height view 영역 사각형의 width, height
용도 UIView에 대한 위치/크기를 정할 때 view transformation 이후 원래 크기를 알아야 할 때
→view 자체의 크기만을 알고 싶을 때
view 내부에 drawRect()로 그릴 때
scrollView에서 스크롤이 일어날 때

 

 

 

 

📌 마치며

bounds 쉽지 않은 놈이다.. 포스팅 작성이 예상보다 엄청 오래 걸렸다ㅠㅠ..

그래도 이렇게 공부할 것들이 많은 만큼, 디테일한 UX / UI 표현이 가능한 것 같다.

 

 

오류 및 지적사항은 댓글로 남겨주시면 감사하겠습니다!

참고 : 

https://jryoun1.github.io/swift/FrameBounds_2/

https://zeddios.tistory.com/203

Comments