Customizable download button with progress and transition animations. It is based on Apple's App Store download button.

Overview

Logo

Pod Version Carthage compatible License Twitter: @hukicamer

AHDownloadButton is a customizable download button similar to the download button in the latest version of Apple's App Store app (since iOS 11). It features download progress animation as well as animated transitions between download states: start download, pending, downloading and downloaded. You can find more details about the implementation on my blog.

Requirements

  • iOS 8.0+
  • Xcode 10.2
  • Swift 5.0

Usage

Code

To use AHDownloadButton in code, you simply create a new instance and add it as a subview to your desired view:

  let downloadButton = AHDownloadButton()
  downloadButton.frame = CGRect(origin: origin, size: size)
  view.addSubview(downloadButton)

The button can have 4 different states:

  • startDownload - initial state before downloading
  • pending - state for preparing for download
  • downloading - state when the user is downloading
  • downloaded - state when the user finished downloading

The state of the button can be changed through its state property.

Delegate

You can use the AHDownloadButtonDelegate to monitor taps on the button and update button's state if needed. To update the current download progress, use the progress property. Here is an example how it could be implemented:

extension DownloadViewController: AHDownloadButtonDelegate {

    func downloadButton(_ downloadButton: AHDownloadButton, tappedWithState state: AHDownloadButton.State)
        switch state {
        case .startDownload:

            // set the download progress to 0
            downloadButton.progress = 0

            // change state to pending and wait for download to start
            downloadButton.state = .pending

            // initiate download and update state to .downloading
            startDownloadingFile()

        case .pending:

            // button tapped while in pending state
            break

        case .downloading:

            // button tapped while in downloading state - stop downloading
            downloadButton.progress = 0
            downloadButton.state = .startDownload

        case .downloaded:

            // file is downloaded and can be opened
            openDownloadedFile()

        }
    }
}

You can also use closures instead of the AHDownloadButtonDelegate by setting the didTapDownloadButtonAction and downloadButtonStateChangedAction properties.

Customisation

AHDownloadButton can be customized. These are the properties that can be used for customizing the button:

  1. Use the custom initializer init(alignment: HorizontalAlignment) to set the horizontal alignment property. HorizontalAlignment determines the position of the pending and downloading circles. The position can either be center , left or right. The default value is center.

  2. Customization properties when button is in startDownload state:

  • startDownloadButtonTitle - button's title
  • startDownloadButtonTitleFont - button's title font
  • startDownloadButtonTitleSidePadding - padding for left and right side of button's title
  • startDownloadButtonHighlightedBackgroundColor - background color for the button when it's in highlighted state (when the user presses the button)
  • startDownloadButtonNonhighlightedBackgroundColor - background color for the button when it's in nonhighlighted state (when the button is not pressed)
  • startDownloadButtonHighlightedTitleColor - title color for the button when it's in highlighted state (when the user presses the button)
  • startDownloadButtonNonhighlightedTitleColor - title color for the button when it's in nonhighlighted state (when the button is not pressed)
  1. Customization properties when button is in pending state:
  • pendingCircleColor - color of the pending circle
  • pendingCircleLineWidth - width of the pending circle
  1. Customization properties when button is in downloading state:
  • downloadingButtonHighlightedTrackCircleColor - color for the track circle when it's in highlighted state (when the user presses the button)
  • downloadingButtonNonhighlightedTrackCircleColor - color for the track circle when it's in nonhighlighted state (when the button is not pressed)
  • downloadingButtonHighlightedProgressCircleColor - color for the progress circle when it's in highlighted state (when the user presses the button)
  • downloadingButtonNonhighlightedProgressCircleColor - color for the progress circle when it's in nonhighlighted state (when the button is not pressed)
  • downloadingButtonHighlightedStopViewColor - color for the stop view in the middle of the progress circle when it's in highlighted state (when the user presses the button)
  • downloadingButtonNonhighlightedStopViewColor - color for the stop view in the middle of the progress circle when it's in nonhighlighted state (when the button is not pressed)
  • downloadingButtonCircleLineWidth - width of the downloading circle
  1. Customization properties when button is in downloaded state:
  • downloadedButtonTitle - button's title
  • downloadedButtonTitleFont - button's title font
  • downloadedButtonTitleSidePadding - padding for left and right side of button's title
  • downloadedButtonHighlightedBackgroundColor - background color for the button when it's in highlighted state (when the user presses the button)
  • downloadedButtonNonhighlightedBackgroundColor - background color for the button when it's in nonhighlighted state (when the button is not pressed)
  • downloadedButtonHighlightedTitleColor - title color for the button when it's in highlighted state (when the user presses the button)
  • downloadedButtonNonhighlightedTitleColor - title color for the button when it's in nonhighlighted state (when the button is not pressed)
  1. transitionAnimationDuration - animation duration between the different states of the button

Special note

AHDownloadButton in startDownload and downloaded states calculates its width based on button title. Use the startDownloadButtonTitleSidePadding and downloadedButtonTitleSidePadding properties to customise the width when the button is in the aforementioned states.

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate AHDownloadButton into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'AHDownloadButton'
end

Then, run the following command:

$ pod install

Author

Amer Hukić

License

AHDownloadButton is licensed under the MIT license. Check the LICENSE file for details.

Comments
  • Can't tap AHDownloadButton which is inside UICollectionViewCell

    Can't tap AHDownloadButton which is inside UICollectionViewCell

    Button is added inside awakeFromNib

    override func awakeFromNib() {
            super.awakeFromNib()
    
            buttonContainer.addSubview(downloadButton)
            downloadButton.snp.makeConstraints { (maker) in
                maker.leading.trailing.equalToSuperview()
                maker.top.equalToSuperview().offset(2)
                maker.bottom.equalToSuperview().offset(2)
            }
        }
    

    but next delegate function isn't called after tap on button

    extension FileViewCell: AHDownloadButtonDelegate {
        func downloadButton(_ downloadButton: AHDownloadButton, tappedWithState state: AHDownloadButton.State) {...}
    }
    

    The workaround is to use touch API:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            for touch in touches {
                if touch.view == downloadButton {
                    downloadButton(downloadButton, tappedWithState: downloadButton.state)
                    break
                }
            }
        }
    

    But it only makes button container UIView tappable:

    @IBOutlet weak var buttonContainer: UIView!
    

    I had a feeling that overriding hitTest somehow could help, but not sure completely, will be thankful if somebody will help to understand what is the proper way of using this button inside collection cell

    opened by kyzmitch 3
  • Unable to leave animationDispatchGroup if app goes to background...

    Unable to leave animationDispatchGroup if app goes to background...

    Unable to leave animationDispatchGroup if app goes to background then back...and the UI is stuck with "startDownload" state

    AHDownloadButton+StateTransitionAnimation.swift

    // My simple fix
    
    //From:
    let completion: (Bool) -> Void = { completed in
        guard completed else { return }
        self.resetStateViews(except: newState)
        self.animationDispatchGroup.leave()
    }
    
    //To:
    let completion: (Bool) -> Void = { completed in
        self.resetStateViews(except: newState)
        self.animationDispatchGroup.leave()
        guard completed else { return }
    }
    
    opened by ykying 2
  • Fixed button title width bug

    Fixed button title width bug

    Was running into a bug where changing the button title string after the initial layout would cause the button width to not recalculate, and either be too wide or too skinny. This happened most often in reusable table view cells that would redraw for different content, in my use-case the button could say "INSTALL" "DOWNLOAD" or "UPDATE" which require 3 different widths, and scrolling on the list it would get out of sync almost immediately.

    Setting the title width back to zero on string didSet causes the width constant to be recalculated on the next layout cycle, which fixes the problem.

    opened by Vortec4800 1
  • Fix bug in example

    Fix bug in example

    This fixes a bug in the example that caused the button to switch to state "downloaded" after the simulated download time even if the download has been cancelled.

    opened by FabioTacke 0
  • Set Deployment Target to iOS 10 in Package.swift

    Set Deployment Target to iOS 10 in Package.swift

    https://github.com/amerhukic/AHDownloadButton/commit/6b78bee9c2959f1634870292e459c4ab0f911ba1 set deployment target to iOS 10, but in Package.swift it's still iOS 8. This PR fixed it.

    opened by xiao99xiao 0
Releases(1.3.0)
Inspired by Apple’s download progress buttons in the app store

GBKUIButtonProgressView Inspired by Apple’s download progress buttons in the app store Created by @pklada and @miketsprague Checkout the blog post. In

Guidebook 541 Sep 1, 2022
Custom loading button with progress swiftui

CustomLoadingButton Simple Custom Loading Progress Button for SwiftUI Version 1.0.0 This version requires Xcode 11+ SwiftUI iOS 13+ macOS 10.15+ Insta

Tariqul 1 Dec 14, 2022
ProgressButton - Custom button class that displays a progress bar around it to gauge

ProgressButton Check it out To run the example project, clone the repo, and open the 'Example/Example.xcodeproj' file. Requirements This component is

Guilherme Moura 116 May 29, 2022
Customizable and easy to use expandable button in Swift.

ExpandableButton Requirements iOS 9.0+ Installation CocoaPods: Add the following line to your Podfile: pod 'ExpandableButton' #for swift less than 4.

Dmytro Mishchenko 98 Dec 5, 2022
Simple and customizable button in Swift

SwiftyButton Maintainer(s): @nickm01 @pmacro @aryamansharda Simple and customizable button in Swift. Installation Cocoapods pod 'SwiftyButton' Cartha

Scoop 542 Dec 13, 2022
Easily customizable floating button menu created with SwiftUI

FloatingButton Easily customizable floating button menu created with SwiftUI We are a development agency building phenomenal apps. Usage Create main b

Exyte 715 Dec 30, 2022
UIButton sublass for loading and transition animation.

TransitionButton Concept Source: Dribbble Preview Expand animation: Shake animation: Example To run the example project, clone the repo, then open the

null 1.4k Dec 25, 2022
A small and flexible (well documented) UIButton subclass with animated loading progress, and completion animation.

ButtonProgressBar-iOS Example For LIVE PREVIEW on Appetize in your browser itself, click here. To run the example project, clone the repo, and run pod

Pushkar Sharma 566 Dec 9, 2022
IGStoryButtonKit provides an easy-to-use button with rich animation and multiple way inspired by instagram story/stories.

Introduction Have you ever seen UI like instagram story, haven't you? Actually, features like instagram story have been implemented in many applicatio

mutation 34 Nov 8, 2022
Animated Play and Pause Button written in Swift, using CALayer, CAKeyframeAnimation.

AnimatablePlayButton Animated Play and Pause Button written in Swift, using CALayer, CAKeyframeAnimation. features Only using CAShapeLayer, CAKeyframe

keishi suzuki 77 Jun 10, 2021
Interactive and fully animated Material Design button for iOS developers.

WYMaterialButton Inspired by Google Material Design, written purely in Swift 3. WYMaterialButton implemented Material Design on iOS and add more dynam

Yu Wang 76 Oct 7, 2022
Cute Animated Button written in Swift.

DOFavoriteButton Cute Animated Button written in Swift. It could be just right for favorite buttons! Requirements iOS 7.0+ Swift 1.2 Installation Cart

Daiki Okumura 3.6k Dec 29, 2022
Floaty is simple floating action button for iOS.

Floaty is simple floating action button for iOS. (formerly KCFloatingActionButton) Why change the name? Follow the swift naming convention. KCF

Lee Sun-Hyoup 1.5k Jan 7, 2023
LTHRadioButton - A radio button with a pretty animation

LTHRadioButton Slightly inspired by Google's material radio button. The clip below has 3 sections: full speed, 25% and 10%, but after converting it to

Roland Leth 368 Dec 16, 2022
Multiple state tap-to-toggle UIButton (like old camera flash button)

Multiple State Toggle UIButton A UIButton subclass that implements tap-to-toggle button text. (Like the camera flash and timer buttons) Usage Just cre

Yonat Sharon 83 Oct 11, 2022
Lickable-Button We made the buttons on the screen look so good you'll want to lick them

Lickable-Button We made the buttons on the screen look so good you'll want to lick them. - Steve Jobs A little SwiftUI button project at WWDC 2021 Lic

Nate Thompson 14 Dec 29, 2021
Craft that perfect SwiftUI button effect 👌🏼

buttoncraft (SwiftUI 3.0 App) Experimenting with SwiftUI 3.0 whilst creating a practical app to craft that perfect button style. ✈️ Testflight https:/

An Trinh 188 Dec 28, 2022
iOS Pod for a Soft UI (Neumorphic) Button for UIKit written in Swift

iOS Pod for a Soft UI (Neumorphic) Button for UIKit written in Swift

Pallav Agarwal 21 Oct 23, 2022
An open-source library to use with SwiftUI, It allows you to create Floating menu action button.

Floating Menu Action Button Example Overview This is an open-source library to use with SwiftUI. It allows you to create Floating menu action button. Ins

ugo 3 Aug 19, 2022