ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [3rd] SkeletonUI 사용법
    🧑‍💻/Swift 2024. 1. 29. 22:47
    반응형

    Framework를 만드는 일은 해봤어도 3rd Party Framework 사용은 많이 안해봐서
    새 프로젝트에 들어갈 때 공부해야할 내용이 많더라구요.
    하나씩 파헤쳐보려 합니다. 러닝 커브가 낮은 Framework 부터...

    Skeleton 이란?

    사용자에게 데이터 로딩중임을 알리고, 데이터 로딩 후에도 자연스럽게 화면이 전환되는 컴포넌트입니다.


    UIKit을 사용한다면 https://github.com/Juanpe/SkeletonView 를 많이 사용하는 것 같더라구요.
    저는 SwiftUI에서 사용할 수 있는 SkeletonUI를 살펴보도록 하겠습니다.


    1. Swift Package Manager 추가

    URL : https://github.com/CSolanaM/SkeletonUI

    2.0.0 버전 사용 시 앱 메모리가 빠른 속도로 증가하는 이슈가 있어서 꼭 2.0.1 이상 버전을 사용해 주세요!

    이렇게 별 일 아닌 것 처럼 fixed를 써 놓다니 ㅠㅠ

    SkeletonUI를 넣었더니 3개의 Package Dependency가 추가되었습니다.

     

    2. 사용 예시 적용해 보기

    SkeletonUI README 가이드에 나온 사용 예시를 실행해 보았습니다.

    예시 1

    skeleton에 true/false 값으로 상태를 체크하고, true이면 그라데이션 애니메이션을 적용해서 보여줍니다.
    5초 뒤에 users에 값을 셋팅해서 skeleton을 종료합니다.

    import SkeletonUI
    import SwiftUI
    
    struct UsersView: View {
        @State var users = [String]()
    
        var body: some View {
            Text("Finished requesting \(users.count) users!")
                .skeleton(with: users.isEmpty)
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                        self.users = ["John Doe", "Jane Doe", "James Doe", "Judy Doe"]
                    }
            }
        }
    }

     

    예시 2

    이번엔 SkeletonList를 사용해서 TableView 형태를 Skeleton으로 표시해 봅니다.
    List 목록에 표시할 양 (quantity) 이나 shape, 라인 수 등 지정할 수 있네요.

    import SkeletonUI
    import SwiftUI
    
    struct User: Identifiable {
        let id = UUID()
        let name: String
    }
    
    struct UsersView: View {
        @State var users = [User]()
    
        var body: some View {
            SkeletonList(with: users, quantity: 6) { loading, user in
                Text(user?.name)
                    .skeleton(with: loading,
                              animation: .pulse(),
                              appearance: .solid(color: .red, background: .blue),
                              shape: .rectangle,
                              lines: 3,
                              scales: [1: 0.5])
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                    self.users = [User(name: "John Doe"),
                                  User(name: "Jane Doe"),
                                  User(name: "James Doe"),
                                  User(name: "Judy Doe")]
                }
            }
        }
    }

     

    3. 활용하기

    위 예시에서 값을 좀 바꿔보았습니다. 이게 더 원래 보던 스켈레톤의 모습 같네요.

    - animation : pulse > linear
    - appearance : solid > gradient
    - shape : rectangle > capsule
    - scales : [1: 0.5] > [0: 0.3, 1: 0.5, 2: 0.7]

    scales[인덱스: 영역비율]라고 생각하시면 됩니다.
    lines 값이 3이니 3줄이 표시될 텐데,
    [0번째 라인은 0.3, 1번째 라인은 0.5, 2번째 라인은 0.7] 만큼 영역을 차지해서 보여줘라! 라는 뜻이죠.
    (혹시나 하고 lines에 1를 넣어 봤는데 1줄만 표시되고 1번째, 2번째 인덱스 값은 무시되네요.)

    struct UsersView: View {
        @State var users = [User]()
    
        var body: some View {
            SkeletonList(with: users, quantity: 4) { loading, user in
                Text(user?.name)
                    .skeleton(with: loading,
                              animation: .linear(),
                              appearance: .gradient(angle: .degrees(30)),
                              shape: .capsule,
                              lines: 3,
                              scales: [0: 0.3, 1: 0.5, 2: 0.7])
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                    self.users = [User(name: "John Doe"),
                                  User(name: "Jane Doe"),
                                  User(name: "James Doe"),
                                  User(name: "Judy Doe")]
                }
            }
        }
    }

     

    나는 SkeletonList 안쓰고 싶고 원래 쓰던 List가 있다. 그 안에 커스텀해서 적용하고 싶다!
    하신다면 다음과 같이 수정할 수 있겠습니다.

    struct UsersView: View {
        @State var users = [User]()
        let quantity = 3
    
        var body: some View {
            List(0..<(users.isEmpty ? quantity : users.count), id: \.self) { index in
                let username = users.count > index ? users[index].name : ""
                Text(username)
                    .skeleton(with: users.isEmpty,
                               animation: .linear(),
                               appearance: .gradient(angle: .degrees(30)),
                               shape: .capsule,
                               lines: 1)
            }
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                    self.users = [User(name: "John Doe"),
                                  User(name: "Jane Doe"),
                                  User(name: "James Doe"),
                                  User(name: "Judy Doe")]
                }
            }
        }
    }

    SkeletonList 구현부를 보면 List로 한 번 감싼 형태입니다.

    반응형

    댓글

Designed by Tistory.