로딩시의 즐거운 진행 표시

지금 개발중인 플레이어! 의 로그인·등록 화면에서, 이런 진척 표시를 하고 있습니다만, 이것 실은 페이크이기도 합니다( ´・‿・`)


(Qiita의 이미지 사이즈 제한이 엄격하고 거칠습니다. 깨끗한 것은 실제로 앱 다운로드하여 참조하십시오.)

경위



원래, 이 화면은 이런 진척 표시는 아니고, 단순히 인디케이터가 빙글빙글 하는 것만으로, 진척 상태를 모르는 것이었습니다.
특히 네트워크가 나쁜 곳이라면 버그가 굳어 버린 것은? 와 사용자를 불안하게 만드는 것 같고, 가끔 그런 목소리를 듣는 일이 있었습니다.
등록 흐름은 중요한 곳이므로, 그런 곳에서 이것이 원인으로 이탈해 버리면 유감이므로, 개선이 필요했습니다.

거기서, 네트워크 처리에도 힘쓰면서도 제대로 정상적으로 처리를 하고 있다는 것을 나타내기 위해서, 진척을 표시하기로 했습니다.

다만, 예를 들면 큰 화상 등 미디어 파일 다운로드 등이라면 어쨌든, 이런 JSON 리스폰스 받는 처리는 세세한 진척을 취할 수 없고, 거기에 의지하면 0%로부터 단번에 100%에 이르는 것 같은 느낌이 되어 버려, 지금 일이었습니다.

본래의 목적은, 「버그는 굳어져 버린 것은?라고 유저를 불안하게 시킨다」같은 상태의 해소이며, 가짜라도 좋기 때문에 왠지 그렇게 할 수 없을까라고 해 보았습니다.

어떤 가짜 진행을 할 것인가?



네트워크 좋은 상태에서도 나쁜 상태에서도, 지와지와 소기미 잘 진척이 진행되어, 안심할 수 있는 느낌을 목표로 했습니다.

몇가지 실험해 보았는데, 등록 처리에 걸리는 시간은 대체로 이하 정도였습니다.
  • 네트워크 좋은 상태: 2-3초 정도
  • 네트워크 나쁜 상태 : 10 초 이상 걸릴 수 있습니다

  • 이것을 바탕으로, 이하가 좋다고 생각해 구현하면, Gif 동영상과 같이 꽤 좋은 느낌이 되었습니다.
  • 네트워크 상태가 나쁜 경우에도 90% 정도까지 10초 정도에 걸쳐 진행이 진행되도록 한다
  • 진척이 진행되는 간격·진행 비율을 랜덤하게 1초 전후 열면서 10% 전후 진행하도록 한다
  • 무작위로 설정하면 가짜 느낌이 사라집니다
  • 처리 중에 10 초 정도 지나면 90 %로 멈추는 것은 허용

  • 네트워크가 좋은 상태에서는, 진척이 절반 부족하고 실제의 처리가 끝나 버리지만, 그 타이밍으로 단번에 100%까지 진행해 소기 좋게 마무리한 느낌으로 해 속여
  • Gif 동영상은이 경로에 가깝습니다


  • 이 실장 후에는, 특히 이것에 관해서 마이너스 의견 듣는 것이 없어졌으므로, 꽤 좋은 소금 매실로 실장 할 수 있었던 것은,이라고 생각하고 있습니다.
    나 자신, 개발중에 「어라, 멈췄다?」라고 생각하는 것이 없어졌습니다.

    덧붙여서 시뮬레이터상에서 저속 회선의 에뮬레이트를 하는 경우는 Network Link Conditioner - NSHipster 를 사용하면 편리합니다.

    구현



    Swift 코드와 SVProgressHUD 라이브러리 을 사용하고 있지만, 간 부분은 다른 플랫폼에서도 마찬가지로 응용할 수 있다고 생각합니다.
    사실은 다른 파일에 정의되어 있는 함수 등 끌어오고, 1개의 코드로서 싣고 있습니다.
    // ヘルパー的な関数群
    func random(num: Int) -> Int {
        return Int(arc4random_uniform(UInt32(num)))
    }
    func random(min: Double, _ max: Double) -> Double {
        let random = Int(arc4random_uniform(UInt32(max*100 - min*100)))
        return min + Double(random) / 100.0
    }
    public func dispatchOnMainThread(delay delay: NSTimeInterval = 0, block: () -> ()) {
        if delay == 0 {
            dispatch_async(dispatch_get_main_queue()) {
                block()
            }
            return
        }
        let d = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(d, dispatch_get_main_queue()) {
            block()
        }
    }
    
    private var progressCompleted = false
    
    /** これがフェイク進捗の肝のメソッド */
    func increaseProgress(progress: Float, message: String?, until: Float = 0.9) {
        if progressCompleted {
            return
        }
        SVProgressHUD.showProgress(min(progress, until), status: message, maskType: .Gradient)
        // 進捗がuntilで設定した最大値を超えたらそれ以上進捗を増やさずに待機
        if progress >= until {
            return
        }
        // ジワジワ動く間隔を0.5〜2秒でランダムに
        let delay = NSTimeInterval(random(0.5, 2))
        dispatchOnMainThread(delay: delay) {
            // 1回の進捗更新でどれくらい進むかを0.05〜0.15でランダムに設定して再帰呼び出し
            self.increaseProgress(progress + Float(random(0.05, 0.15)), message: message, until: until)
            return
        }
    }
    
    /** サインアップ処理 */
    private func signUpImpl() {
        progressCompleted = false
        increaseProgress(0.05, message: message)
        // 実際のログイン処理を呼ぶ
        // ...
    
        // 終わったら100%に進める
        progressCompleted = true
        SVProgressHUD.showProgress(1, status: message, maskType: .Gradient)
    }
    

    좋은 웹페이지 즐겨찾기