본문 바로가기
아이폰 개발/Swift

swift custom loading view, custom indicator

by 인생여희 2021. 10. 25.

swift custom loading view, custom indicator

 

만들어볼 custom indicator

 

네트워크 통신을 할때, 앱위에 로딩뷰나 인디케이터를 띄워준다. 사용자에게 무언가가 일어나고있다는 걸 보여주고, 작동중이니 걱정말라는 표시도 될 수 있다. 너무 길어지면 안되겠지만.

 

위 그림처럼 start 버튼을 누르면 이미지가 다양하게 바뀌면서 loading view 를 띄워주거나, indicator 를 띄워주는 예제를 정리해보았다.

 

 

먼저 loading view는 아래와 같이 스토리 보드로 만들어주었다. UIView type의 커스텀 클래스를 하나 만들어서 스토리 보드와 이어준다. 

 

 

loading view나 custom indicator 만드는 방법은 여러가지가 있을 것 같다. 

 

나는 custom view를 이용했고, timer를 이용했다. 

 

그리고 이미지이름 배열을 이용해서 timer 0.3초마다 이미지가 바뀌도록 처리했다. 

 

메소드는 시작 함수와 종료 함수를 만들었다. 

 

그럼 IndicatorView를 어디서 호출해주나?


import UIKit

class IndicatorView: UIView {

    var timer:Timer?
    @IBOutlet weak var loadingImage: UIImageView!
    @IBOutlet weak var loadingLabel: UILabel!
    
    
    let imageNames = ["wand.and.rays" , "wand.and.rays.inverse", "wand.and.stars", "wand.and.stars.inverse"]
    
    //MARK: 초기화
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadXib()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        loadXib()
    }

    //MARK: Xib 로드
    private func loadXib(){
        
        //self 는 최상위 view - 보이지 않음
        self.tag = 100
        
        let identifier = String(describing: type(of: self))
        let nibs = Bundle.main.loadNibNamed(identifier, owner: self, options: nil)
        
        // 첫번째 Nib 중에서 첫번째 View
        guard let customView = nibs?.first as? UIView else {return}
        customView.frame = self.bounds
        customView.backgroundColor = UIColor(white: 1, alpha: 0.3)
        //customView.tag = 100
        self.addSubview(customView)
    }
    
    //MARK: 시작
    public func startLoading(){
        var i = 0
        timer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true) { timer in
            if i >= self.imageNames.count { i = 0 }
            self.loadingImage.image = UIImage(systemName: self.imageNames[i])
            i += 1
        }
    }
    
    
    //MARK: 정지
    public func stopLoading(){
        timer?.invalidate()
    }
    
    
}

 

 

IndicatorView는 어느화면에서 꼭 필요한 화면이다. 그렇기 때문에 싱글톤 클래스를 만들어서 그 싱글톤 클래스가 indicatorVIew를 컨트롤할 수있게 해보았다. 

 

아래 처럼 Center 라는 싱글톤 클래스를 만들어주고 , indicatorView를 띄워주는 함수, 숨기는 함수를 만들었다. 그리고 indicator view, loading view를 최상위 view 위에 띄워야 되므로, 최상위 view를 구하는 함수도 만들어 주었다.

 

import Foundation
import UIKit
class Center {
    
    //MARK: 로딩뷰
    var indicatorView:IndicatorView?
    
    static let shared = Center()
    private init(){ }
    
    //MARK: 보이기
    func showLoadingPage(_view:UIViewController) {

        let width = getRootViewController(vc: _view)?.view.frame.size.width ?? 0
        let height = getRootViewController(vc: _view)?.view.frame.size.height ?? 0

        indicatorView = IndicatorView(frame: CGRect(x: 0, y: 0, width: width , height: height))
        
        if let indicatorView = indicatorView {
            indicatorView.startLoading()
            self.getRootViewController(vc:_view)?.view.addSubview(indicatorView)
        }

    }

    //MARK: 숨기기
    func hideLoadingPage(_view:UIViewController) {
        
        // loading View의 tag 는 100
        if let loadingView = self.getRootViewController(vc: _view)?.view.viewWithTag(100) {
            
            indicatorView?.stopLoading()
            loadingView.removeFromSuperview()
        
        }
    }
    
    /**
     # getRootViewController
     - Author: k
     - Date:
     - Parameters:
        - vc: rootViewController 혹은 UITapViewController
     - Returns: UIViewController?
     - Note: vc내에서 가장 최상위에 있는 뷰컨트롤러 반환
    */
    public func getRootViewController(vc:UIViewController) ->UIViewController?{

    
        ///[1] 네비게이션 컨트롤러
        if let nc = vc as? UINavigationController {

            if let vcOfnavController = nc.visibleViewController {
                return self.getRootViewController(vc: vcOfnavController)
            }
        
        ///[2] 탭뷰 컨트롤러
        }else if let tc = vc as? UITabBarController {
            
            if let tcOfnavControler = tc.selectedViewController {
                return self.getRootViewController(vc: tcOfnavControler)
            }
            
        ///[3] 뷰 컨트롤러
        }else{
            if let pvc = vc.presentedViewController{
                return self.getRootViewController(vc: pvc)
            }else {
                return vc
            }
        }
        
        return nil
    }

}

 

 

그리고 마지막으로 아래와 같이 위에서 만든 싱글톤 클래스를 사용해서 indicator 를 호출해주면 끝~

 

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func showLoadingImag(_ sender: UIButton) {
        print("ViewController - showLoadingImag")
        Center.shared.showLoadingPage(_view: self)
        _ = Timer.scheduledTimer(withTimeInterval: 6, repeats: false) { _ in
            Center.shared.hideLoadingPage(_view: self)
        }
        
    }
    @IBAction func stopAction(_ sender: UIButton) {
        print("ViewController - stopAction")

    }
    
}

 

 

IndicatorView.swift
0.00MB
IndicatorView.xib
0.00MB
Center.swift
0.00MB
ViewController.swift
0.00MB