<aside> 💡 TableView, CollectionView는 ScrollView를 상속받고 있다.
</aside>
contentOffset
var contentOffset: CGPoint { get set }
- scroll view의 origin에서 content view의 origin까지 얼마나 떨어졌는지를 나타내는 좌측상단의 포인트. scrollView Bounds의 origin point값
- 콘텐트 뷰의 원점이 스크롤뷰의 원점과 상쇄되는 지점으로 스크롤할 때마다 contentoffset이 변한다.
- contentOffset이 변하면 스크롤된다.
- 기본값은 CGPointZero(0,0)이다.
<aside> 💡 CGPoint
CGPoint는 2차원 좌표계를 표현하는 점으로 x,y값(double형식)을 갖고 있음
CGSize
너비 및 높이값을 포함하는 구조체
width, height변수를 갖고 있음, zero는 static 변수로 높이와 너비가 모두 0인 크기
CGRect
CGPoint타입의 변수 origin, CGSize타입의 변수 size를 갖고 있음, 따라서 origin은 좌표를! size는 너비와 높이를!
</aside>
Bounds
Bounds를 변경하는 것은 해당위치에서 View를 다시 그리라는 의미가 된다. Bounds는 상위뷰와 아무런 관련이 없으므로, subView가 움직이는 것처럼 보인다.
[Swift] frame과 bounds에 대해서 알아보자 - 2
view의 bounds의 origin을 변경하는 것을 view의 자체좌표계에서 viewport를 (x,y)로 이동하는 것이다.
viewport는 실제로 화면이 보여지는 창을 의미한다. 휴대폰 기기의 화면 사이즈는 크지 않기 때문에 화면사이즈보다 큰 view의 경우에는 일부분만 보여지게 된다. 따라서 휴대폰 사이즈보다 큰 view의 경우에는 viewport만큼만 화면에 보여지게 된다. 이때 bounds origin을 변경하는 것은 viewport를 x,y만큼 이동시키는 것이다.
contentSize
scrollView의 모든 content가 들어있는 영역을 말한다.
UIEdgeInsets
View와의 거리를 나타낸다. 구조체타입으로 특정 레이아웃을 줄이거나 커지게 한다. 또는 간격이 생기거나 레이아웃을 넘거나 한다. 양수값을 크리를 줄이게 해주거나 안쪽으로 간격이 생기게 해준다.
margin, padding개념이라고 생각하면 된다.
MainRunLoop
앱이 실행되면 ios는 내부적으로 메인스레드에서 main run loop를 실행한다.
IOS는 UI를 업데이트 할 때, 업데이트하는 일정의 시간을 두어서 UI렌더링은 값비싼 작업이기에 효율적으로 업데이트하기위해 main run loop를 만들었다.
main run loop동안에 app은 사용자의 이벤트를 받아들이고 개발자가 짜놓은 코드에 따라 적절한 response를 취해준다.
response가 다 취해지고 다시 main loop에 return이 되면 이제 update cycle로 진입하게 된다. update cycle은 layout을 재배치하거나 view들을 다시 그리는 작업을 진행하게 된다.
그래서 이벤트 핸들링중에 뷰를 변화시키는 요청이 들어오면 이 update cycle에서 갱신을 해주는 작업을 진행한다. 하지만 뷰를 즉각적으로 갱신하고 싶은 경우, setNeedsLayout()메서드 혹은 layoutIfNeeded메서드를 사용한다. 두 메서드가 호출되면 공통적으로 view를 갱신하는 메서드인 layoutSubviews가 호출된다.
두가지 상태로 구성 → 사용자의 터치 이벤트나 뷰의 레이아웃을 인식하는 main run loop와 뷰들의 layout을 constraint하는 구조로 존재
UpdateCycle - 내부에서 메서드를 실행하여 아래와 같은 뷰의 정보를 업데이트
- constraint(auto layout에서 사용하는 제약조건)
- Layout(Size, Point)
- Display(Color, text, image)
실행되는 메서드 순서는 updateConstraints > layoutSubviews > draw 로 이 세가지 메서드는 값 비싼 비용이 들기 대문에 개발자가 호출하지 못하고 main run loop의 update cycle에서 내부적으로 호출되는 형태이다.
layoutSubviews()
view와 모든 subview들의 위치와 사이즈를 재계산하여 배치시켜준다.
layoutSubviews()는 재귀적으로 자식들의 layoutSubviews()도 재귀적으로 실행한다.
그래서 이 메서드는 매우 expensive하며 공식문서에 따르면 이 함수를 직접 호출할 수 없고, setNeededsLayout()과 layoutIfNeeded()를 통해서 뷰를 갱신하라고 말한다.
layoutSubviews()실행시점은 main run loop에 따라서 실행된다. UI를 건드리는 작업은 디바이스에 부담이 되는 작업이므로 내부적으로 UI작업에 main run loop라는 방법을 통해 해결한다.
setNeedsLayout(), layoutIfNeeded()
view의 layout을 갱신시키는 메서드들이다.
둘의 차이점은 언제 갱신을 하는 지이다.
setNeedLayout은 다음 updateCycle에, layoutIfNeeded는 즉시 갱신해달라고 요청하는 메서드이다.
layoutIfNeeded()
호출되면, queue맨 앞쪽에 넣어서 곧바로 UI가 변경되기를 기대할 수 있음. | |
호출되면, update cycle을 바로 실행하여 레이아웃이 즉각적으로 적용 |
하지만 아래와 같은 상황은 위 메서드를 호출하지 않아도 시스템에서 바로 layoutSubviews()를 호출한다.
- View의 크기를 조절할 때(Resizing a view)
- Subview를 추가할 때(Adding a subview)
- 사용자가 UIScrollView를 스크롤할 때(User scrolling a UIScrollView (layoutSubviews is called on the UIScrollView and its superview))
- 디바이스를 회전시켰을 때 (Portrait, Landscape)(User rotating their device)
- View의 Auto Layout constraint 값을 변경시켰을 때(Updating a view’s constraints)
setNeedsLayout() vs layoutIfNeeded 차이점
Auto Layout을 사용할 때, layoutIfNeeded를 호출하면 변경된 제약을 만족하도록 뷰의 레이아웃이 바뀐다. == 뷰의 frame이 바뀐다
뷰의 frame은 애니메이션이 가능한 속성이다.
- layoutIfNeeded()
topConstraint.constant = 100
DispatchQueue.main.async {
self.view.layoutIfNeeded()
}
→ 호출결과는
viewWillLayoutSubviews
viewDidLayoutSubviews
- setNeedsLayout()
topConstraint.constant = 100
DispatchQueue.main.async {
self.view.setNeedsLayout()
}
→ 호출결과는
viewwilllayoutsubview
viewDidLayoutSubviews
viewwilllayoutsubview
viewDidLayoutSubviews
이유
그냥 레이아웃이 수정되면 사이클에서 반영을 하는데, 이때 layoutsubview()가 호출되면 각각 viewWillLayoutSubviews, viewDidLayoutSubviews가 호출된다.
하지만 수동으로 레이아웃 변경을 updateCycle에서 반영해달라고 요청하는데 그런 함수인 layoutIfNeeded, setNeedsLayout은 다음과 같은 차이가 있다.
'개발일기 > IOS' 카테고리의 다른 글
[Swift] - UIGestureRecognizer (0) | 2024.03.15 |
---|---|
[Swift] - View의 Cycle (0) | 2024.03.15 |
[Swift] - Animation 정리 1 (0) | 2024.03.15 |
[Swift] - CollectionView 정리 (0) | 2024.03.15 |
[Swift] - ViewController 화면전환 (0) | 2024.03.15 |