Litle Dev
Litle Dev

Reputation: 493

Horizontal Linear Progress Bar like Android in iOS

How to do I implement a horizontal progress bar in iOS like as Android.

Progressbar in iOS like Android

I have tried the following, and found a solution like deteminate.

func startSendPickUpRequestShakeTimer () {

        if self.movingViewTimer == nil {
            self.movingViewTimer =  Timer.scheduledTimer(
                timeInterval: TimeInterval(movingViewSpeed),
                target      : self,
                selector    : #selector(self.startAnimating),
                userInfo    : nil,
                repeats     : true)
        }
}

func startAnimating() {

        let movingViewX = movingView.frame.minX >= view.frame.maxX ? 0-movingView.frame.width-forwardX:movingView.frame.minX + forwardX

        self.movingView.frame = CGRect(x: movingViewX, y: movingView.frame.minY, width: movingView.frame.width, height: moviewViewHeight)

}

But how can I implement the others, or is there any good resource to do that?

Upvotes: 16

Views: 13966

Answers (3)

berbie
berbie

Reputation: 1028

I added this extension to UIProgressBar that animates a 40pt wide bar from left to right and back

extension UIProgressView {

    func startAnimateIndeterminate() {

        // When bar exists, it's animating
        guard indeterminateAnimationBar == nil else { return }

        let width = 40.0
        let animationDuration = 1.0
        let endPos = bounds.width-width

        // `UIProgressView` contains two image views, the background and the animation bar which is the last.
        // The animation bar has a cap resizable image which is pulled from here and inserted into an own bar
        // instance that can be managed independently.
        guard let original = self.subviews.filter({ $0 is UIImageView }).last as? UIImageView else { return }
        let bar = UIImageView(image: original.image)
        bar.restorationIdentifier = "IndeterminateBar"
        bar.frame = CGRect(origin: .zero, size: .init(width: width, height: bounds.height))
        addSubview(bar)

        func animate() {
            UIView.animate(withDuration: animationDuration, animations: {
                bar.frame.origin.x = endPos
            }, completion: { [weak self] _ in
                if self?.indeterminateAnimationBar == nil { return }
                UIView.animate(withDuration: animationDuration, animations: {
                    bar.frame.origin.x = 0
                }, completion: { [weak self] _ in
                    if self?.indeterminateAnimationBar == nil { return }
                    animate() // Repeat animation
                })
            })
        }
        animate()
    }

    func stopAnimateIndeterminate() {
        // When bar exists, it's animating. Then remove from superView which will also stop the animation.
        guard let bar = indeterminateAnimationBar else { return }
        bar.removeFromSuperview()
    }

    var indeterminateAnimationBar: UIImageView? {
        subviews.filter { $0 is UIImageView && $0.restorationIdentifier == "IndeterminateBar" }.last as? UIImageView
    }
}

Upvotes: 0

Kamran Bashir
Kamran Bashir

Reputation: 795

I had coded this extension for indetermined progress in ios. Maybe this can help

extension UIProgressView{
    private struct Holder {
        static var _progressFull:Bool = false
        static var _completeLoading:Bool = false;
    }
    
    var progressFull:Bool {
        get {
            return Holder._progressFull
        }
        set(newValue) {
            Holder._progressFull = newValue
        }
    }
    
    var completeLoading:Bool {
        get {
            return Holder._completeLoading
        }
        set(newValue) {
            Holder._completeLoading = newValue
        }
    }
    
    func animateProgress(){
        if(completeLoading){
            return
        }
        UIView.animate(withDuration: 1, animations: {
            self.setProgress(self.progressFull ? 1.0 : 0.0, animated: true)
        })
        
        progressFull = !progressFull;
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) {
            self.animateProgress();
        }
    }
    
    func startIndefinateProgress(){
        isHidden = false
        completeLoading = false
        animateProgress()
    }
    
    func stopIndefinateProgress(){
        completeLoading = true
        isHidden = true
    }
}

Fiverr: https://www.fiverr.com/kamranbashir

Upvotes: 5

Markymark
Markymark

Reputation: 2979

This is now part of Material components for iOS. https://material.io/develop/ios/components/progress-indicators/progress-views

pod 'MaterialComponents/ProgressView'

import MaterialComponents.MaterialProgressView

Code sample:

    let progressView = MDCProgressView()
    progressView.mode = .indeterminate        
    progressView.progressTintColor = .white
    progressView.trackTintColor = UIColor.white.withAlphaComponent(0.2)
    progressView.startAnimating()
    
    view.addSubview(progressView)
    //Then set constraints for your view (I used SnapKit https://github.com/SnapKit/SnapKit)
    progressView.snp.makeConstraints { (make) in
        make.left.equalTo(header.snp.left)
        make.right.equalTo(header.snp.right)
        make.top.equalTo(header.snp.bottom).offset(20)
        make.height.equalTo(4)
    }

Upvotes: 0

Related Questions