SwiftUI - Page banner 만들기

Whale·2022년 6월 15일
1

오늘의 목표. 많이들 쓰는 페이징 기능이 달린 배너 만들어보기.

어플리케이션을 만들다보면 한번쯤은 보게되는 페이징 배너.
여기에 한쪽방향으로 무한하게 움직이게 해달라거나, 양 옆에 이전, 다음 배너가 살짝(?) 걸치게 만들어달라는 등의 커스텀 요청을 많이 받곤 한다.

Swift UI 를 손대기 시작한지 얼마 되지 않았으니 아주 간단하게, 기본기능에 충실하게 만들어보는게 목표.

ScrollView 를 이용한 제작방법.

제일 처음 만들 방법을 생각해본건 ScrollView 를 이용한 제작방법이었다.
GeometryReader(세부사항은 다음 포스트에) 를 통해 상위 뷰의 크기를 잡고, 스크롤뷰를 깔고, 안에 대상이 되는 아이템들을 이미지로 넣어준다.

프리뷰에 보이진 않지만 좌우로 잘 움직인다. 이제 pagingEnable 을 설정해주면 되는데...

pagingEnable 은 없습니다.

또없다. 이게 또... 없다고 한다.(오토레이아웃이 없던것보다는 충격이 덜했지만)
해결방법은 UIScrollView에 접근해서 appearance 속성까지 타고들어가야 한다고 했다.
뷰의 라이프 사이클의 onAppear , onDisaooear 를 붙여서 이 뷰가 사용되는 동안만 UIScrollView.appearance 속성을 변경해보기로 했다.

struct ImageScrollBannerView: View {
    var body: some View {
        
        GeometryReader { geo in
            let w = geo.size.width
            let h = w
            
            ScrollView(.horizontal, showsIndicators: true, content: {
                LazyHStack(spacing: 0) {
                    ForEach(1..<5) { index in
                        Image("animal_0\(index)")
                            .resizable()
                            .frame(width: w, height: h)
                            .aspectRatio(contentMode: .fit)
                    }
                }
            })
            .frame(width: w, height: h)
            .onAppear {
                UIScrollView.appearance().isPagingEnabled = true
            }.onDisappear {
                UIScrollView.appearance().isPagingEnabled = false
            }
        }
    }
}

UIScrollview 의 appearance 를 건드리는게 상당히 찜찜했지만, 일단 여기까지 완성.
이제 UIPageController 를 ZStack 으로 위에 표기하면 될거같았는데...

PageController 도 없습니다.

pagingEnable 이 없을때 알아챘어야 했다. 활성화가 안되는데 컨트롤러가 있을리가 있나.
새삼 내가 UIKit 에 많은 도움을 받고있었음을 알수있었다.

결국 완성본처럼 만들려면 pageController 를 직접구현하거나, UIKit 의 컴포넌트를 랩핑하여 Swift UI 에서 사용해야 한다는 결론에 도달했다.

두가지 모두 하나의 포스트에 담기에는 내용이 방대해서 고민하고 있었는데, 역시나. 다른 방법으로 간단하게 구현하는것이 가능하다고 한다.

TabView 를 통한 구현

TabView 는 하단에 있는 셀렉트 박스와 함께 쓰는걸로 생각이 고정되어있었는데, Swift UI 에서는 TabView 의 스타일을 지정함으로서 Container View와 같은 개념으로도 사용이 가능한것 같았다.

코드는 스크롤뷰를 베이스로 직접 구현하는 방법보다 매우 심플하다.

struct ImageScrollBannerView: View {
    var body: some View {
        
        GeometryReader { geo in
            let w = geo.size.width
            let h = w
            
            TabView {
                ForEach(1..<5) { index in
                    Image("animal_0\(index)")
                        .resizable()
                        .frame(width: w, height: h)
                        .aspectRatio(contentMode: .fit)
                }
            }
            .tabViewStyle(.page)
            .frame(width: w, height: h)
        }
    }
}

아예 하단 Page Controller 까지 붙여서 나와주는 심플함.
TabView 를 쓰는것처럼 아이템을 쭉 추가하고 마지막에 .tabViewStyle(.page) 만 붙여주면 알아서, 편하게 만들어준다.

마무리

하지만 실제 디자이너의 요구를 받는다고 가정하면 TabView 를 쓰는 기본기능으로는 한계가 있을것이 분명했다. 기왕 공부를 시작한김에 스크롤뷰를 이용한 방법으로 완성시켜보려 한다.
그를 위해선 GeometryReaderPreferenceKey 에 대한 이해가 먼저 선결되어야 한다.
두가지 모두 다음 포스트에서.

profile
그저 오래된 iOS 개발자.

0개의 댓글