iOS/Tip

IndicatorView

까칠코더 2016. 12. 22. 15:29
반응형

IndicatorView

작업 수행중에 사용자 입력을 막아야 할때가 있다. 
이때 IndicatorView를 띄워주면 편하다.

class IndicatorView {
    
    var container = UIView()
    var loadingView = UIView()
    var activityIndicator = UIActivityIndicatorView()
    
    static let shared: IndicatorView = {
        return IndicatorView()
    } ()
    
    func show(parentView: UIView) {
        container.frame = parentView.frame
        container.center = parentView.center
        container.backgroundColor = UIColor(0x000000, alpha: 0.3)
        
        loadingView.frame = CGRect(x:0, y:0, width:100, height:100)
        loadingView.center = parentView.center
        loadingView.backgroundColor =  UIColor.black
        loadingView.clipsToBounds = true
        loadingView.layer.cornerRadius = 10
        
        activityIndicator.frame = CGRect(x:0, y:0, width:40, height:40)
        activityIndicator.activityIndicatorViewStyle = .whiteLarge
        activityIndicator.center = CGPoint(x:loadingView.frame.size.width / 2, y:loadingView.frame.size.height / 2);
        
        loadingView.addSubview(activityIndicator)
        container.addSubview(loadingView)
        parentView.addSubview(container)
        activityIndicator.startAnimating()
    }
    
    func show() {
        guard let keyWindow = UIApplication.shared.keyWindow else {
            return
        }
        
        if #available(iOS 10.0, *) {
            keyWindow.layoutIfNeeded()
        }
        
        DispatchQueue.main.async {
            self.show(parentView:keyWindow)
        }
    }
    
    func hide() {
        DispatchQueue.main.async {
            self.activityIndicator.stopAnimating()
            self.container.removeFromSuperview()
        }
    }
}

사용법

IndicatorView.shared.show()

IndicatorView.shared.hide()


IndicatorView에 타임아웃 적용하기

타이머 시간을 지정하여 일정시간 동작이 없으면 자동으로 숨김처리

typealias CompletionHandler = () -> Swift.Void

/**
 특정 작업중에 사용자의 조작을 막기 위해 IndicatorView를 띄워준다.
 
 일정시간동안 작업이 완료되지 않아 hide()나 또 다른 show() 메소드를 
 명시적으로 실행하지 못하는 경우에는 타임아웃이 동작하여 자동으로 hide() 시킨다.
 
 ```
 IndicatorView.shared.show(3) {
    UIAlertView.show(withTitle: nil, message: "타이머 종료", cancelButtonTitle: nil, otherButtonTitles: ["확인"], tap: nil)
 }
 ```
 */
class IndicatorView {
    static let shared: IndicatorView = {
        return IndicatorView()
    } ()
    
    private var timeout = Double.infinity
    private var waitingTimer : Timer?
    private var container = UIView()
    private var loadingView = UIView()
    private var activityIndicator = UIActivityIndicatorView()
    private var timeoutHandler: CompletionHandler?
    
    private func show(parentView: UIView) {
        container.frame = parentView.frame
        container.center = parentView.center
        container.backgroundColor = UIColor(0x000000, alpha: 0.3)
        
        loadingView.frame = CGRect(x:0, y:0, width:100, height:100)
        loadingView.center = parentView.center
        loadingView.backgroundColor =  UIColor.black
        loadingView.clipsToBounds = true
        loadingView.layer.cornerRadius = 10
        
        activityIndicator.frame = CGRect(x:0, y:0, width:40, height:40)
        activityIndicator.activityIndicatorViewStyle = .whiteLarge
        activityIndicator.center = CGPoint(x:loadingView.frame.size.width / 2, y:loadingView.frame.size.height / 2);
        
        loadingView.addSubview(activityIndicator)
        container.addSubview(loadingView)
        parentView.addSubview(container)
        activityIndicator.startAnimating()
    }
    
    /**
     타임아웃 발생시 IndicatorView를 hide()시키고 
     디버그 모드일때만 Toast 메시지를 보여준다.
     */
    @objc private func timeoutOccurred() {
        timeoutHandler?()
        hide()
    }
    
    /**
     타이머 시작시 기존 타이머는 정지하고 다시 시작한다.
     */
    private func startTimer() {
        if let timer = waitingTimer {
            timer.invalidate()
            waitingTimer = nil
        }
        
        waitingTimer = Timer.scheduledTimer(timeInterval: timeout, target: self, selector:#selector(IndicatorView.timeoutOccurred), userInfo: nil, repeats: false)
    }
    
    /**
     타이머 멈추기
     */
    private func stopTimer() {
        waitingTimer?.invalidate()
        waitingTimer = nil
        timeoutHandler = nil
    }
    
    /**
     IndicatorView를 보여주며 타이머를 시작한다.
     
     - Parameter timeout: 타임아웃 시간 (default = 30, 무제한 : Double.infinity)
     - Parameter timeoutHandler: 타임아웃이 발생한 경우 처리할 동작 (default = nil)
     */
    func show(_ timeout: Double = 30, timeoutHandler: CompletionHandler? = nil) {
        guard let keyWindow = UIApplication.shared.keyWindow else {
            return
        }
        
        self.timeout = timeout
        self.timeoutHandler = timeoutHandler
        startTimer()
        
        keyWindow.layoutIfNeeded()
        
        DispatchQueue.main.async {
            self.show(parentView:keyWindow)
        }
    }
    
    /**
     IndicatorView를 숨기며 타이머를 종료한다.
     */
    func hide() {
        stopTimer()
        
        DispatchQueue.main.async {
            self.activityIndicator.stopAnimating()
            self.container.removeFromSuperview()
        }
    }
}

사용법
3초 뒤에도 IndicatorView가 없어지지 않으면 알림창 띄워준다.

IndicatorView.shared.show(3) {
    UIAlertView.show(withTitle: nil, message: "타이머 종료", cancelButtonTitle: nil, otherButtonTitles: ["확인"], tap: nil)
}


반응형