ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • lottie-ios 프레임워크와 UIViewRepresentable 을 이용한 LoadingView 구현
    SwiftUI/MVVM 알아보기 2020. 8. 27. 20:44

    로띠(lottie) 는 json 형식의 움직이는 이미지 포맷으로 aribnb에서 개발되었고 많은 웹이나 앱에서 사용되고 있다. UIKit과 SwiftUI에서는 직접 이를 지원하지 않으므로 lottie-ios 프레임워크를 Pod을 통해 설치하고 이를 통해서 LottieView를 구현할 수 있다. 

    SwiftUI는 지원하지 않는 UIKit의 WebView 나 MapView등 사용하기 위해 UIViewRepresentable 프로토콜을 정의하고 있고 이를 구현함으로 써 쉽게 이를 SwiftUI로 전환 할 수 있다. 여기서는 lottie-ios 프레임워크와 UIViewRepresentable 프로토콜 구현을 통해 LottieView를 구현하고 이를 통해 날씨 정보를 로딩 하는 중 이를 화면에 표시하는 LodingView를 구현하는 것으로 날씨 앱 구현을 마무리한다. 

     

    lottie-ios는 terminal 에서 아래와 같이 설치할 수 있다. 이미 Cocoa Pods 이 설치되어 있으면 첫번째 과정은 수행하지 않는다.  

    Cocoa Pods 설치 

    $ sudo gem install cocoapods 
    $ pod setup —verbose

    Cocoa Pods 에서 lottie-ios 설치 

    현재 Project 폴더로 이동한 후 현재 프로젝트에서 아래와 같이 수행 
    $ pod init
    $ open Podfile
    
    Podfile에 pod 'lottie-ios' 추가 
    
    Podfile 내용 
    
    # Uncomment the next line to define a global platform for your project
    # platform :ios, '9.0'
    
    target 'ClimaForSwiftUI' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for ClimaForSwiftUI
      pod 'lottie-ios'
    
      target 'ClimaForSwiftUITests' do
        inherit! :search_paths
        # Pods for testing
      end
    
      target 'ClimaForSwiftUIUITests' do
        # Pods for testing
      end
    
    end
    
    수정 완료후 프레임워크 설치를 위해 아래와 같이 입력
    
    $ pod install
    $ open .
    
    
    이후 프로젝트파일(.xcodeproj) 파일이 아닌 워크스페이스(.wcworkspace) 파일을 클릭해 XCode를 재 실행한다. 

    LottieView 구현

    LottieView는 lottie-ios 프레임워크의 AnimationView를 생성하고 이를 UIView의 하위뷰로 설정한 후 이를 반환하는 팩토리 함수와 해당

    뷰를 업데이트하는 함수를 가지는 UIViewRepresentable 프로토콜을 구현해야 한다. 이를 구현한 LottieView는 아래와 같다.  

    LottieView.swift

    import SwiftUI
    import Lottie
    
    struct LottieView: UIViewRepresentable {
        var filename: String
        //UIViewRepresentable 프로토콜의 UIView 팩토리 메서드 구현
        func makeUIView(context: Context) -> UIView {
            let view = UIView(frame: .zero)
            //로디 애니메이션 뷰 생성
            let animationView = AnimationView()
            //애니메이션 파일 설정
            animationView.animation = Animation.named(filename)
            //에니메이션 스케일 설정
            animationView.contentMode = .scaleAspectFit
            //애니메이션 시작
            animationView.play()
            animationView.translatesAutoresizingMaskIntoConstraints = false
            //해당 에니메이션 뷰를 생성할 View의 하위뷰로 설정
            view.addSubview(animationView)
            
            //상위뷰의 크기로 애니메이션 뷰의 크기 설정
            NSLayoutConstraint.activate([
                animationView.widthAnchor.constraint(equalTo: view.widthAnchor),
                animationView.heightAnchor.constraint(equalTo: view.heightAnchor)
                                                     
            ])
            return view
        }
        //UIViewRepresentable 프로토콜의 UIView 업데이트 메서드 구현
        func updateUIView(_ uiView: UIView, context: Context) {
          
        }
    }
    
    
    

     

    이제 LottieView를 통해 LodingView를 아래와 같이 구현한다. 

    LoadingView.swift

    import SwiftUI
    
    struct LoadingView: View {
        var body: some View {
            VStack(alignment: .center) {
                Spacer()
                LottieView(filename: "data")
                Text("Loading...").font(.title)
                    .foregroundColor(.gray)
                Spacer()
            }.frame(width: 200, height: 200)
            .background(Color(red: 0.965, green: 0.969, blue: 0.972))
            .cornerRadius(20)
                .shadow(color: /*@START_MENU_TOKEN@*/.black/*@END_MENU_TOKEN@*/, radius: /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/, x: 20, y: 20)
        }
    }
    
    struct LoadingView_Previews: PreviewProvider {
        static var previews: some View {
            LoadingView()
        }
    }

    이제 WeatherViewModel은 날씨 정보를 가져올 때 로딩 뷰를 화면에 보여주고 완료시 로딩뷰를 화면에서 없애고 날씨 정보가 보이도록 isLoading 플래그를 추가하고 private func load(resource:) 함수 시작과 종료시 플래그를 변경하도록 한다. 

     

    WeatherViewModel.swift

    class WeatherViewModel : ObservableObject {
        ...
        @Published var isLoading : Bool = false
    }
    
    extension WeatherViewModel {
        ... 
        private func load(resource: Resource<WeatherData>) {
            isLoading = true
            URLRequest.load(resource: resource) { (result) in
                switch result {
                case .success(let weatherData) :
                    self.model = weatherData
                case .failure(let error) :
                    print(error)
                }
                self.isLoading = false
            }
        }
    }
    

    이제 해당 뷰 모델을 관찰하고 있는 뷰는 isLoading 의 변경을 통지 받을 수 있고 이를 통해서 true일 때 로딩화면을 표시하고 false일 때 로딩화면을 제거할 수 있게 된다. 

    ContentView.swift

    struct ContentView: View {
        ...  
        var body: some View {
            ZStack {
                ...
                if viewModel.isLoading {
                    LoadingView()
                }
            }
        }
    }

    지금 까지 SwitUI를 이용해 날씨 앱을 구현한 전체 프로젝트는 아래에 추가한다.

     

    ClimaForSwiftUI.tar.gz
    0.22MB

    'SwiftUI > MVVM 알아보기' 카테고리의 다른 글

    SwiftUI 에서 CoreLocation 사용  (0) 2020.08.27
    SwiftUI MVVM 모델  (0) 2020.08.27
    iOS 의 MVC 모델  (0) 2020.08.26

    댓글

Designed by Tistory.