UICollectionView, UITableView는 프로젝트를 진행할 때 매우 많이 사용하고, 이 둘은 UIScrollView를 상속하고 있다. UIScrollView도 많이 사용해 보긴 했지만... 쓸 때마다 정확히 알아보지도 않고 사용해서 테이블 뷰의 페이징 기능을 구현해 보려고 할 때 좀 정확하게 알아야겠다 싶어서 알아보게 되었다.
UIScrollView의 작동 방식
UIScrollView는 UIView와 크게 다르지 않다. frame이 있고, bounds가 있다. frame은 해당 뷰의 원점이 해당 뷰의 원점으로부터 얼만큼 떨어졌는지를 좌표계로 나타낸 것이고, bounds는 자기 자신의 원점을 기준으로 좌표계로 나타낸 것이다.
이때 부모뷰의 bounds의 원점을 변경 하면 자식뷰의 frame이 변경되어서 움직이는 것처럼 보이게 된다.
이를 이용해 UIScrollView도 자신의 bounds를 변경 해 내부 콘텐츠뷰를 스크롤할 수 있게 했다.
이를 좌표계로 표현해 보면 다음과 같다.
- 회색 배경(해당 이미지 자체)은 스크롤뷰의 부모 뷰
- 회색 내부의 투명한 창이 스크롤 뷰
- 빨간색, 노란색, 파란색 등이 있는 곳이 스크롤 뷰의 콘텐츠뷰
스크롤 뷰의 콘텐츠뷰는 내부 bounds의 좌표계에 의해 위치가 변경된다. 즉 위 영상처럼 스크롤 뷰 자체의 bounds의 원점이 변경되면서 스크롤이 일어나게 되는 것이다.
Frame Layout Guide, Content Layout Guide
스토리 보드에서 ScrollView를 끌어서 뷰에 두면 ScrollView 내부에 Frame Layout Guide와 Content Layout Guide가 있는 것을 볼 수 있다.
Content Layout Guide
내부 콘텐츠 뷰를 기준으로 레이아웃을 잡을때 사용한다. UIScrollView의 콘텐츠 뷰는 콘텐츠뷰의 내부 요소들의 크기에 의해 결정된다. 뷰 안에 서브뷰를 넣어, 그 서브뷰의 레이아웃을 잡으려고 할 때 사용한다고 보면 된다.
스크롤 뷰 내부에 파란색 뷰를 넣고 content Layout Guide에 top, bottom, trailing, leading에 각각 50씩 constraint를 넣으면 저렇게 constraint가 들어간 것을 볼 수 있다. 근데 trailing과 bottom은
이런 식으로 서브뷰에서 contentLayoutGuide를 기준으로 잡아버린다. 왜 이런지는 아직 모르겠다. 그래서 contentViewLayoutGuide 내부에 서브뷰가 다 들어가길 원한다면 bottom과 trailing은 음수값을 줘서 잡아야지 다 들어간다.
Frame Layout Guide
ScrollView의 frame을 기준으로 레이아웃을 잡을 때 사용한다. 그래서 한쪽 방향으로 스크롤 하려고 할 때 스크롤 뷰 자체의 높이가 너비를 똑같이 해 한쪽으로만 스크롤을 할 수 있도록 사용하는데 많이 사용한다.
ContentOffset
스크롤뷰의 bounds의 원점과 contentView의 원점이 떨어진 지점을 나타낸다. 스크롤뷰의 bounds가 기준. 테이블뷰나 컬렉션뷰에서 페이징 기능을 구현할 때, ContentOffset을 사용하여 구현한다.
ScrollView의 contentView와 safeArea
ScrollView의 frame이 safeArea가 아닌 SuperView를 기준으로 레이아웃이 잡혀 있어도 내부 contentView는 SafeArea에 가려지지 않기 위해 contentOffset을 조정한다.
이게 무슨소리냐면...
이런 식으로 UIScollView의 레이아웃이 safeArea를 기준으로 잡힌 게 아닌, superView로 잡혀있어도 (ScrollView의 최상/하단에 라벨을 붙여 둠)
이렇게 contentView는 스크롤 뷰를 기준이 아닌, safeArea를 기준으로 스크롤을 가능하게 자동으로 조정해 준다.
즉 이렇게 ScrollView가 TabBar나 NavigationBar 같은 SafeArea를 기준으로 잡혀있지 않아도 알아서 ContentOffset을 조절해 줘서 내부 content가 다 보이게 해 준다.
이때 UITableViewController를 사용하거나 UICollectionViewController를 사용해서 페이징 기능을 구현해야 할 때 contentOffset에 변화가 생기게 되므로 SafeArea를 포함한 contentOffset을 계산해야 한다.
대표적인 예시로 탭바를 적용한 예시가 있다.
ScrollView 자체는 SuperView를 기준으로 오토레이아웃이 잡혀 있지만, ScrollView의 콘텐츠 뷰는 TabBar에 의해 contentOffset이 탭바의 높이만큼 더 추가되었다. 따라서 위와 같은 상황에서 마지막까지 스크롤을 했는지 contentOffset으로 확인을 할 때 식은 다음과 같게 된다.
if scrollView.contentOffset.y >= (scrollView.contentSize.height-(scrollView.frame.height-tabBarController!.tabBar.frame.height)) {
// 마지막 까지 스크롤 했을 경우 수행할 작업
}
'iOS > UIKit' 카테고리의 다른 글
DiffableDatasource (0) | 2023.09.19 |
---|---|
UICollectionViewCompositionalLayout (0) | 2023.09.17 |
UIView와 CALayer (0) | 2023.07.26 |
CAShapeLayer, CABasicAnimation을 이용하여 버튼 누를 시 원이 그려지는 애니메이션 + 애니메이션이 완료되었을 때 원하는 작업 수행하기 (0) | 2023.06.01 |
뷰가 화면에 그려지는 과정 - Constraints, Layout (0) | 2023.04.28 |