IndicatorView

iOS/Tip 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)
}


반응형

'iOS > Tip' 카테고리의 다른 글

바코드 생성하기 (Code128, QRCode)  (0) 2017.02.24
SwipeGesture를 ScrollView와 함께 사용하기  (0) 2017.01.31
EUC-KR / CP949 문자열 처리 하기  (0) 2017.01.20
WKWebView에서 Cookies 사용하기  (0) 2017.01.05
JavaScript to Native  (0) 2016.12.21
Autolayout 우선순위  (0) 2016.12.14
URLSession 사용시 참고  (0) 2016.12.08
메모리 정보 가져오기  (0) 2016.11.30
Posted by 까칠코더
,