SwiftUI

SwiftUI - PinnedScrollableViews (a.k.a Sticky View)

GREEN.1229 2022. 11. 21. 17:33

안녕하세요. 그린입니다🍏

이번 포스팅에서는 SwiftUI에서 PinnedScrollableViews라는것에 대해 알아보겠습니다🙌

 

이걸 알아보게 된 배경은 프로덕트의 기능을 구현하다 스크롤뷰로 감싸진 VStack에서 헤더 뷰를 구성하고 이 헤더 뷰는 스크롤을 아무리 내려도 상단에 고정시켜야 했습니다.

이에 LazyVStack 구현 시 파라미터에 pinnedViews라는 옵션이 있었어요.

pin하니까 역시 무언가 고정해준다는 느낌을 확 받았고, 이 타입은 PinnedScrollableViews라는것을 알게되었습니다.

참고로 이러한 뷰를 Sticky View라고 부릅니다😊

 

그럼 우선 PinnedScrollableViews가 무엇인지 알아보고 적용해보시죠!

 

PinnedScrollableViews?

iOS 14에서부터 사용가능하며 스크롤 뷰의 경계에 고정을 시켜줄 수 있는 뷰 타입 집합입니다.

선언은 아래와 같습니다.

struct PinnedScrollableViews

해당 타입은 staic 변수로 기본적으로 두개의 고정 위치 선택을 위한 값을 제공해줍니다.

sectionHeaderssectionFooters를 통해 상 / 하단 원하는 위치에 고정이 가능하죠.

또한 조금 더 커스텀하게 UInt32의 원시값을 이용해 PinnedScrollableViews를 직접 만들 수 있습니다.

 

요정도면 알면 충분합니다!
그럼 바로 사용해보도록 하죠🕺🏻

 

LazyVStack에서 PinnedScrollableViews 사용해 상단 고정 스크롤 뷰 만들기

말보다 코드부터😀
import SwiftUI

// StickyView
struct ContentView: View {
  let colors: [Color] = [.red, .green, .yellow, .black, .gray, .blue, .brown, .purple, .orange]
  
  var body: some View {
    VStack {
      TitleView()
      
      ScrollView(showsIndicators: false) {
        ScrollTitleView()
        
        LazyVStack(pinnedViews: .sectionHeaders) {
          Section(header: HeaderView()) {
            VStack {
              ForEach(colors, id: \.self) { color in
                CellItemView(color: color)
                  .padding(.horizontal, 10)
              }
            }
          }
        }
      }
    }
  }
}

private struct TitleView: View {
  fileprivate var body: some View {
    Text("Variant Colors")
      .font(.largeTitle)
      .bold()
  }
}

private struct ScrollTitleView: View {
  fileprivate var body: some View {
    Text("ScrollView Start Point")
      .font(.largeTitle)
      .bold()
  }
}

// Sticky Header
private struct HeaderView: View {
  fileprivate var body: some View {
    HStack {
      Spacer()
      Text("This is Header")
        .font(.title)
        .bold()
        .foregroundColor(.blue)
      Spacer()
    }
    .background(.white)
  }
}

private struct CellItemView: View {
  private var color: Color
  
  fileprivate init(color: Color) {
    self.color = color
  }
  
  fileprivate var body: some View {
    RoundedRectangle(cornerRadius: 20)
      .foregroundColor(color)
      .frame(height: 100)
  }
}

우선 코드가 간단해서 다른 부분은 생략하고 중요한 부분만 설명하겠습니다.

LazyVStack 생성 시 pinnedViews 조건을 sectionHeaders로 줍니다.

그럼 스티키하게 헤더는 상단에 고정되죠!

그 다음 Section header에 만든 HeaderView를 담아줍니다.

그러면 이제 정말 고정된 스크롤 헤더 뷰 완성🚀

그 밑으로는 자유롭게 구성해주면 됩니다🙌

 

여기서 중요한점은 Sticky Header를 만들때 background를 주지 않으면 오버레이처럼 중첩되어 나타나보입니다.

아래와 같이 말이죠😭

 

이런 불상사를 막기 위해 Sticky Header를 만들때 background의 색상을 white로 주면 충분해집니다.

아마도 PinnedScrollableViews를 위해 만들어지는 Header의 백그라운드는 clear해서 그런것 같아요.

그럼 이제 돌려보죠!

 

챠란~~ 원하는 결과를 얻었습니다. (+1)

 

마무리

Sticky 구현을 처음 해봤는데 아주 유용하고 요긴하게 두루두루 휘뚜루마뚜루 잘 쓸것 같습니다👍

위 예시 코드는 제 깃헙 레포에 있으니 필요하다면 참고해주세요😀

https://github.com/GREENOVER/playground/tree/main/PinnedScrollableViews

 

GitHub - GREENOVER/playground: 학습을 하며 간단한 예제들을 만들어 보는 작고 소중한 놀이터

학습을 하며 간단한 예제들을 만들어 보는 작고 소중한 놀이터. Contribute to GREENOVER/playground development by creating an account on GitHub.

github.com

 

[참고 자료]

https://developer.apple.com/documentation/swiftui/pinnedscrollableviews

 

Apple Developer Documentation

 

developer.apple.com