ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SkeletonUI
    Library 2022. 7. 25. 10:30

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

    이번 포스팅에서는 아주 예전부터 궁금했었는데 까먹고 있던 라이브러리 하나 보고 가려고합니다ㅎㅎ

    바로 SkeletonUI 라는 외부 라이브러리입니다.

    데이터를 받아올때 패칭이 완료되기전에 빈 공간으로 UI를 보여주는것보다 아래와 같은 이러한 데이터가 들어올 영역에 대해 뼈대를 잡는것이라 보면 될것 같아요.

    이로 인해 조금 더 자연스러운 UI 경험을 시켜줄 수 있으며 빈 뷰로 나오면 버그라고 인식하기 쉬운 반면 이런것들을 적용시켜두면 로딩중이구나~ 라고 인식할 수 있어 사용자 경험에 더 좋은 영향을 끼칩니다🙌

     

    그럼 이걸 쉽게 구현해놓은 SkeletonUI에 대해 알아보시죠!

    아마 아주 간단할것 같아요 이번 포스팅은ㅎㅎ

     

    SkeletonUI?

    공식 리드미에서의 설명이 아주 간단히 되어 있어요.

    SkeletonUI는 스켈레톤 방식의 로딩 애니메이션을 선언적인 구문을 통해 구현할 수 있게 해주었습니다.

    로딩 화면 혹은 인디케이터를 사용하지 않고 스켈레톤 UI 방식을 이용해 동일한 효과를 나타낼 수 있으며 구현할 수 있습니다🙌

     

    SkeletonUI 특징 및 장점

    리드미에서 소개하는 특징이자 장점을 제가 추려서 소개해보겠습니다.

    - 선언적인 SwiftUI와 잘 어울림

    - 쉽고 간편한 설정

    - 모든 뷰에 적용 가능하며 커스텀화도 가능

    - 아이폰, 아이패드, 애플티비, 애플워치 등등 모든 플랫폼에 범용적임

    - 가벼운 코드 기반

     

    SkeletonUI 지원 버전

    - macOS 10.15 이상

    - Xcode 11.0 이상

    - Swift 5.0 이상

    - iOS 13.0 이상

    - tvOS 13.0 이상

    - watchOS 6.0 이상

    SwiftUI를 사용하는 환경이라면 잘 어울리고 선언적 UI다 보니 쓰기 좋을것 같다고 생각했는데 전혀 문제가 되지 않겠네요!

     

    SkeletonUI 설치

    SPM과 코코아팟 두가지를 지원합니다.

    아쉽지만 카르타고는 지원하지 않습니다🥲

    SPM으로 설치 시 아래와 같이 Package 파일에 디펜던시를 추가해줍니다.

    dependencies: [
    .package(url: "https://github.com/CSolanaM/SkeletonUI.git", .branch("master"))
    ]

    CocoaPods으로 설치 시는 팟 파일에 아래 팟을 추가해줍니다.

    pod 'SkeletonUI

    끝~~~~🥳

     

    SkeletonUI 사용

    이제 사용해볼까요?

    아주 간단합니다.

    예제는 리드미에 나온 예제를 가지고 테스트 해보겠습니다.

    [기본 사용]

    import SwiftUI
    import SkeletonUI
    
    struct SkeletonView: View {
      @State var colors = [String]()
      
      var body: some View {
        VStack {
          Spacer()
            .frame(height: 350)
          Text("Colors data download is completed")
            .skeleton(with: colors.isEmpty)
          Spacer()
            .frame(height: 350)
        }
        .onAppear {
          DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.colors = ["GREEN", "RED", "BLUE", "YELLOW", "BLACK"]
          }
        }
      }
    }

    위와 같이 적용시킬 뷰에 skeleton 메서드를 호출해줍니다.

    저는 colors 프로퍼티가 비어있을때 스켈레톤 UI 뷰와 애니메이션이 노출되게 구현해줬어요.

    이게 정해진 기본 사용 방식입니다.

    당연히 색상 및 형태 지정을 해주려면 아래 커스텀 사용처럼 해줘야하겠죠.

    우선 기본 사용을 통한 결과는 아래와 같습니다.

    [커스텀 사용]

    import SwiftUI
    import SkeletonUI
    
    struct CustomSkeletonView: View {
      @State var colors = [Color]()
      
      var body: some View {
        SkeletonList(with: colors, quantity: 10) { loading, color in
          Text(color?.name)
            .skeleton(with: loading)
            .shape(type: .rectangle)
            .appearance(type: .solid(color: .red, background: .blue))
            .multiline(lines: 3, scales: [1: 0.5])
            .animation(type: .pulse())
        }
        .onAppear {
          DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            self.colors = [
              Color(name: "GREEN"),
              Color(name: "RED"),
              Color(name: "BLUE"),
              Color(name: "BLACK")
            ]
          }
        }
      }
    }
    
    struct Color: Identifiable {
      let id = UUID()
      let name: String
    }

    이렇게 Color를 리스트로 뿌려주고 이에 대해 커스텀한 스켈레톤 뷰를 만들 수 있습니다.

    SkeletonList 내부를 살펴보죠.

    import SwiftUI
    
    @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
    public struct SkeletonList<Data, Content>: View where Data: RandomAccessCollection, Data.Element: Identifiable, Content: View {
        private let data: Data
        private let quantity: Int
        private let content: (Bool, Data.Element?) -> Content
    
        public init(with data: Data, quantity: Int = 1, @ViewBuilder content: @escaping (Bool, Data.Element?) -> Content) {
            self.data = data
            self.quantity = quantity
            self.content = content
        }
    
        public var body: some View {
            List(0 ..< (data.isEmpty ? quantity : data.count), id: \.self) { index in
                self.content(self.data.isEmpty, self.data.isEmpty ? nil : self.data.map { $0 }[index])
            }
        }
    }

    이렇게 내부 구현이 구성되어 있어요.

    즉 content라는 클로저 안에 Bool 타입 즉 로딩이 되었는지를 판별할 수 있겠죠?

    data는 정말 그대로 데이터로 들어올것들이에요.

    그리고 quantity는 스켈레톤 뷰로 리스트를 띄워줄 셀의 갯수로 보면 됩니다.

    데이터가 4개여도 저 값을 10개로 지정해두면 스켈레톤 뷰를 띄워줄때 10개의 셀로 보여지고 데이터를 다 리스폰 받으면 4개만 정상적으로 보여집니다.

    그 외 형태, 컬러, 애니메이션 효과, 셀 내 라인 수 등 커스텀하게 제작할 수 있어요.

    그럼 최종적으로 위의 구현은 아래와 같이 될 수 있습니다.

     

    마무리

    해보고 싶었던 아주 간단한 라이브러리였는데 이렇게 해보네요.

    내부 구현도 까보니 어렵지 않고 직접 만들어 적용도 해볼 수 있겠더라구요..!?

    조금 더 좋은 사용 경험을 위해 스켈레톤 구현은 필수적으로 생각이 드네요🤔

    위 예제를 보고 커스텀하게 구현한 제 코드도 같이 공유드립니다🙌

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

     

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

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

    github.com

     

    [참고자료]

    https://github.com/CSolanaM/SkeletonUI

     

    GitHub - CSolanaM/SkeletonUI: ☠️ Elegant skeleton loading animation in SwiftUI and Combine

    ☠️ Elegant skeleton loading animation in SwiftUI and Combine - GitHub - CSolanaM/SkeletonUI: ☠️ Elegant skeleton loading animation in SwiftUI and Combine

    github.com

    https://axelhodler.medium.com/creating-skeleton-loaders-in-swiftui-b8f005612814

     

    Creating Skeleton Loaders in SwiftUI

    In our apps we often populate lists with content that is fetched from elsewhere. Some server or service somewhere on the internet.

    axelhodler.medium.com

    'Library' 카테고리의 다른 글

    SwiftUI-Introspect  (2) 2022.09.15
    TCACoordinators  (6) 2022.08.15
    코코아팟 배포 타겟 관련 컴파일 오류 해결하기  (2) 2022.07.05
    R.swift  (2) 2022.06.06
    NukeUI  (0) 2022.06.02
Designed by Tistory.