CircleProgressButton icon indicating copy to clipboard operation
CircleProgressButton copied to clipboard

UIView based circle button with CAShapeLayer based progress stroke.

CircleProgressButton

UIView based circle button with CAShapeLayer based progress stroke.

platforms Carthage compatible Cocoapods pod

Requirements

  • iOS9+
  • Swift4.2

How to use

Customize Appearance

Colors and icon images are fully customizable. Either override or set preferred values.
Actually there's no default appearance, so have fun.👋

    open var defaultImage: UIImage?
    open var inProgressImage: UIImage?
    open var suspendedImage: UIImage?
    open var completedImage: UIImage?
    open var inProgressStrokeColor: UIColor?
    open var suspendedStrokeColor: UIColor?
    open var completedStrokeColor: UIColor?
    open var strokeMode: StrokeMode = .fill
    open var touchedAlpha: CGFloat = 0.5
    public var animated: Bool = true

UIImage's contentMode is .center. Make sure you provide correct size of image.

Update progress and state

  • state: updates color and icon image
  • progress: updates stroke progress
  • reset(): mutates both state and progress
  • complete(): mutates both state and progress

It is possible to update progress while suspended.
state is read-only. Update via suspend(), resume(), complete() and reset().

Disable/Enable Animations

By default implicit CALayer's animations are enabled. You can disable or enable this behavior either by

  • mutating animationEnableOptions property
  • Use CircleProgressButton#animate(animationEnableOption:_:) or CircleProgressButton#performWithoutAnimation(animationEnableOption:_:)

Handle Tap

    private var token: CircleProgressButton.DisposeToken?

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        token = button.onTap { state in
             switch state {
             case .inProgress:
                print("suspend")
                self.suspendJob()
             case .completed:
                print("delete")
                self.cancelJob()
             case .default:
                print("start")
                self.resumeJob()
             case .suspended:
                print("resume")
                self.resumeJob()
             }
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        token?.dispose()
    }

Using on UITableViewCell or UICollectionViewCell

Make sure you layout before letting CircleProgressButton to calculate the circleWidth.

SeeAlso:

  • Example
  • https://github.com/toshi0383/CircleProgressButton/issues/7
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as! TableViewCell

        // IMPORTANT:
        //   frame is .zero after the first initialization of this cell.
        //   Make sure layout before letting CircleProgressButton.framework to calculate the `circleWidth`.
        cell.layoutIfNeeded()

        cell.circleProgressButton.progress = 50
        cell.circleProgressButton.resume()

        return cell
    }

Using RxSwift

    override func viewDidLoad() {
        super.viewDidLoad()
        button.tapGesture.rx.event
            .subscribe(...)
            // ...
    }

For advanced touch interaction..

Feel free to assign your UIGestureRecognizerDelegate.

    button.tapGesture.delegate = self

License

MIT