An iOS/tvOS photo gallery viewer, useful for viewing a large (or small!) number of photos.

Overview

This project is unmaintained.

Alex passed away in an accident in late 2019. His love of iOS development will always be remembered.

AXPhotoViewer Build Status

Demo GIF #1 Demo GIF #2

AXPhotoViewer is an iOS/tvOS photo viewer that is useful for viewing a very large (or very small!) amount of images and GIFs. This library supports contextual presentation and dismissal, interactive "flick-to-dismiss" behavior, and easily integrates with many third party async image downloading/caching libraries.

How to use

While AXPhotoViewer has many configurable properties on each of its modules, it is easy to throw down some initialization code and get started:

let dataSource = AXPhotosDataSource(photos: self.photos)
let photosViewController = PhotosViewController(dataSource: dataSource)
self.present(photosViewController, animated: true)

Force touch implementation?

It's easy to implement force touch with this library by using PreviewingPhotosViewController:

func previewingContext(_ previewingContext: UIViewControllerPreviewing,
                      viewControllerForLocation location: CGPoint) -> UIViewController? {

    guard let indexPath = self.tableView.indexPathForRow(at: location),
        let cell = self.tableView.cellForRow(at: indexPath),
        let imageView = cell.imageView else {
        return nil
    }

    previewingContext.sourceRect = self.tableView.convert(imageView.frame, from: imageView.superview)

    let dataSource = AXPhotosDataSource(photos: self.photos, initialPhotoIndex: indexPath.row)
    let previewingPhotosViewController = PreviewingPhotosViewController(dataSource: dataSource)

    return previewingPhotosViewController
}

func previewingContext(_ previewingContext: UIViewControllerPreviewing,
                      commit viewControllerToCommit: UIViewController) {

    if let previewingPhotosViewController = viewControllerToCommit as? PreviewingPhotosViewController {
        self.present(PhotosViewController(from: previewingPhotosViewController), animated: false)
    }
}

Objective-C interoperability

This library fully supports interop between Objective-C and Swift codebases. If you run into any issues with this, please open a Github issue or submit a pull request with the suggested changes.

Installation

Installation can easily be done through Cocoapods:

pod install 'AXPhotoViewer'

If you prefer not to use Cocoapods, add the contents of the 'Source' directory to your project to get started.

Note: If you don't use Cocoapods, you must add MobileCoreServices.framework, QuartzCore.framework, and ImageIO.framework to your project.

Configuration

There are many configurable properties that can be set before presenting your AXPhotosViewController.

For example, on the AXPhotoDataSource object, you may set up the data source with an initial page index, as well as being able to control the rate at which the library will download additional photos.

let photos = [first, second]
let dataSource = AXPhotosDataSource(photos: photos, initialPhotoIndex: 1, prefetchBehavior: .aggressive)

On the AXPagingConfig object, you may set up the configuration with a different navigation orientation (horizontal vs vertical scrolling between pages), inter-photo spacing (the spacing, in points, between each photo), and/or a custom loading view class that will be instantiated by the library as needed.

let pagingConfig = AXPagingConfig(navigationOrientation: .horizontal, interPhotoSpacing: 20, loadingViewClass: CustomLoadingView.self)

Lastly, but surely not least, is the AXTransitionInfo configuration. This can be used to customize all things related to the presentation and dismissal of your AXPhotosViewController, including the starting reference view, the ending reference view, the duration of the animations, and a flag to disable/enable interactive dismissals.

let transitionInfo = AXTransitionInfo(interactiveDismissalEnabled: false, startingView: self.startingImageView) { [weak self] (photo, index) -> UIImageView? in
    // this closure can be used to adjust your UI before returning an `endingImageView`.
    return self?.endingImageView
}

Custom views

It's very simple to add a custom self-sizing view to the view hierarchy of the photo viewer by accessing properties on the OverlayView. The topStackContainer and bottomStackContainer are exactly what they sound like, anchored to either the top or bottom of the overlay. All that is necessary to add your custom view to these containers is the following:

photosViewController.overlayView.topStackContainer.addSubview(customSubview1)
photosViewController.overlayView.bottomStackContainer.addSubview(customSubview2)

These views will be sized and stacked in the order that they are added. It's possible to re-order these subviews to fit your needs.

Network Integrations

A network integration, in relation to this library, is a class conforming to the AXNetworkIntegration protocol. This protocol defines some methods to be used for downloading images, as well as delegating their completions (and errors) to the library. If you wish to create your own module for async downloading/caching of images and gifs, the protocol is fairly lightweight.

Some pre-defined AXNetworkIntegrations have already been made as Cocoapod subspecs (SDWebImage, PINRemoteImage, AFNetworking, Kingfisher, Nuke..., as well as a simple network integration using NSURLSession that will serve most people's purposes quite sufficiently). To use these pre-defined subspecs, simply change your Podfile:

pod install 'AXPhotoViewer/Lite'
pod install 'AXPhotoViewer/SDWebImage'
pod install 'AXPhotoViewer/PINRemoteImage'
pod install 'AXPhotoViewer/AFNetworking'
pod install 'AXPhotoViewer/Kingfisher'
pod install 'AXPhotoViewer/Nuke'

To create your own AXNetworkIntegration:

pod install 'AXPhotoViewer/Core'
let customNetworkIntegration = CustomNetworkIntegration() // instantiate your custom network integration
let dataSource = AXPhotosDataSource(photos: self.photos)
let photosViewController = PhotosViewController(dataSource: dataSource, networkIntegration: customNetworkIntegration)

Enabling Nuke's support for GIFs

Nuke's support for downloading GIFs is disabled by default. If you want support for GIFs, you have to enabled it.

ImagePipeline.Configuration.isAnimatedImageDataEnabled = true

More details here: Nuke animated images

Customization

As mentioned earlier, there are many configurable properties on each of the modules of the photo viewer, and you can access those modules through the AXPhotosViewController. For instance, you may replace the default loading view, caption view, and/or overlay title view with your own. These views must be self sizing, and conform to the AXLoadingViewProtocol, AXCaptionViewProtocol, and AXOverlayTitleViewProtocol respectively.

let pagingConfig = AXPagingConfig(loadingViewClass: CustomLoadingView.self) // custom loading view class to be instantiated as necessary
...
photosViewController.overlayView.captionView = CustomCaptionView() // custom caption view
photosViewController.overlayView.titleView = CustomTitleView() // custom title view

The AXPhotosViewController and its modules are very extensible, so subclassing each is an easy feat to accomplish without breaking other areas of the library.

Contributions

If you see something you would like changed, I'm open to ideas! Open a Github issue if you see something wrong, or fork the repo and open a pull request with your changes. I'd be happy to look them over!

Comments
  • How to hide the share icon in the photo viewer?

    How to hide the share icon in the photo viewer?

    Hi Alex,

    Just let me say this first... very awesome library, saved me a ton of time. Thank you for making this and sharing this. Using Kingfisher loader too.

    One quick question I have, is there an easy way to hide the share icon? I didn't see some option when I looked around.

    Thank you,

    Chris

    opened by chrisvoronin 6
  • loses count on swipe and then crashes

    loses count on swipe and then crashes

    Its not working for me. It loses count on swipe and then crashes. For example, when i swipe to the final photo, and then try and swipe for one more, the count goes down and it loses track of the count, and then, ultimately, swiping through more of the photos, it crashes.

    opened by goodbox 5
  • NukeIntegration undeclared identifier

    NukeIntegration undeclared identifier

    I have in my podfile: pod 'AXPhotoViewer' pod 'AXPhotoViewer/Nuke'

    And then in my source: import AXPhotoViewer import Nuke .... let integration = NukeIntegration()

    I get undeclared identifier for NukeIntegration

    What am I missing here? Thanks in advance.

    opened by gdetari 4
  • internalTitle localization in PhotosViewController

    internalTitle localization in PhotosViewController

    Hi, There is a small fix in fileprivate func updateOverlay(for photoIndex: Int)

    517 self.overlayView.internalTitle = NSLocalizedString("(photoIndex + 1) of (self.dataSource.numberOfPhotos)", comment: "")

    It must be somelike ...

    self.overlayView.internalTitle = "(photoIndex + 1) " + NSLocalizedString("of", comment:"") + " (self.dataSource.numberOfPhotos)"

    ... to get easy localized version. Or you can use String.localizedStringWithFormat to cover some difficult cases like Arabic language and so on.

    opened by DarkwingXL 3
  • ios 8?

    ios 8?

    Would it be straightforward to walk the minimum iOS version back to 8.0? For this and for AXStateButton? I've got an application in mind that could use a cool image gallery like this but I'd like to target iOS 8 as well.

    enhancement 
    opened by drmarkpowell 3
  • Customising the actionBarButtonItem and closeBarButtonItem via subclassing the PhotosViewController

    Customising the actionBarButtonItem and closeBarButtonItem via subclassing the PhotosViewController

    I was trying to override the actionBarButtonItem and closeBarButtonItem (just for the look and feel) via subclassing the PhotosViewController. The Swift compiler have this warning "Overriding non-open var outside of its defining module". To get this working, I have to change the method declaration from public to open. I wonder if this the only option for just changing the look and feel.

    bug 
    opened by deepmode 3
  • How to reload update?

    How to reload update?

    Is there a built in functionality to reload an updated model? For example we currently let user update the caption. However, I don't see a way to reload a photoAtIndexPath?

    Also is there a way to delete an item out of datasource?

    opened by chrisvoronin 2
  • 1.6.1 build failed, 17 issues

    1.6.1 build failed, 17 issues

    1.5.0 worked fine. 1.6.1 gives 17 errors.

    Environment

    • swift 4.0
    • target iOS 10.0

    I guess I need to update to swift 4.2 too. Thanks for your effort on this amazing photo viewer.

    screen shot 2018-09-23 at 12 26 02 pm

    opened by Hardtack1 2
  • Dismiss finish completion or delegate?

    Dismiss finish completion or delegate?

    Hi,

    I want to know if there's a way to know when the PhotoViewerController did finish dismiss (by both close button and interactive animation) ?

    Thank you,

    enhancement 
    opened by Amefuri 2
  • Crash on animated dismmissing controller.

    Crash on animated dismmissing controller.

    Lib version: AXPhotoViewer (1.3.6) AXStateButton (1.1.4)

    crash at line 226 at file AXPhotosTransitionController

    photosViewController.currentPhotoViewController at the moment of dismiss have nil value,

    guard let imageView = photosViewController.currentPhotoViewController?.zoomingImageView.imageView as UIImageView? else { assertionFailure("No. ಠ_ಠ") return }

    P.S. It so funny and so "professional" have this smiles instead description text inside crash log?

    bug 
    opened by ndarmancev 2
  • " url = nil" does not seem to work.

    To insert an image of an asset, do the following:

    for i in 0 ..< images.count - 1 { manager.requestImage(for: images[i], targetSize: CGSize(width: 100, height: 100.0), contentMode: .aspectFill, options: nil) { (result, _) in print(result) let resultphoto = Photo(image: result, url: nil) self.photos.append(resultphoto)
    }

    I have obviously put nil in the url, but I keep trying to download it. The image is imported from the asset.

       self.urlSession.dataTask(with: self.photos[indexPath.row].url!) { [weak self] (data, response, error) in
            guard let uData = data else {
                return
            }   
    

    I get an error here.

    opened by eastswift 2
  • Moving resources to resource bundle

    Moving resources to resource bundle

    Hello @justindhill! You wrote that you still come here from time to time to maintain the repository. This is a wonderful and simple library with many ready-to-go integrations that we are to this day using in our app.

    We want to optimise our pod installation process: at the times of Xcode 10 we had to add :disable_input_output_paths => true to Podfile to mitigate CocoaPods/CocoaPods#8122. These days we found that every other pod moved to using resources_bundle except this one. I wrote a simple PR ( #81 ) to fix this. It would be cool if you could merge it and add version 1.7.2 tag to the master branch.

    Thank you in advance!

    opened by OneSman7 3
  • Moving resources to resource bundle

    Moving resources to resource bundle

    This fixes build errors on new build system. Currently only this pod in our app is using resources rather than resources_bundle. These changes will allow us to remove :disable_input_output_paths => true from Podfile. See this issue - https://github.com/CocoaPods/CocoaPods/issues/8122

    opened by OneSman7 0
  • RIP, Alex!

    RIP, Alex!

    I used this pod 2 years ago, and now that I'm looking for a photo viewer again, I stumbled upon this repo. Thanks Alex for making this project! Indeed your love for iOS engineering will always be remembered.

    Glenn

    opened by glennposadas 6
  • Fix warning: MobileCoreServices has been renamed. Use CoreServices instead.

    Fix warning: MobileCoreServices has been renamed. Use CoreServices instead.

    Close #78

    If our library was installed via CocoaPods, Xcode 11.4 will issue the warning "MobileCoreServices has been renamed. Use CoreServices instead.".

    image

    How to fix: Do not explicitly link MobileCoreServices.framework in the CocoaPods generated project, by deleting MobileCoreServices from the spec.frameworks attribute in our podspec file.

    More info: https://github.com/AFNetworking/AFNetworking/pull/4532

    opened by ElfSundae 0
Releases(v1.7.1)
Owner
Alex Hill
Alex passed away in late 2019. His love of iOS development will always be remembered.
Alex Hill
Jogendra 113 Nov 28, 2022
A photo gallery for iOS with a modern feature set. Similar features as the Facebook photo browser.

EBPhotoPages ”A photo gallery can become a pretty complex component of an app very quickly. The EBPhotoPages project demonstrates how a developer coul

Eddy Borja 1.7k Dec 8, 2022
A modern photo viewing experience for iOS.

NYTPhotoViewer NYTPhotoViewer is a slideshow and image viewer that includes double-tap to zoom, captions, support for multiple images, interactive fli

The New York Times 2.8k Jan 5, 2023
Source code for iOS app "Photos for VK" — albums and photos manager for social network VKontakte

VK Photos (formally Photos for VK) VK Photos is an iOS app for manage albums and photos in social network VKontakte (vk.com) Screenshots Disclaimer ⚠️

Yury S. 29 Oct 8, 2022
This simple cordova plugin will download picture from an URL and save to IOS Photo Gallery.

Photo Viewer This plugin is intended to download a picture from an URL into IOS Photo library.. How to Install Cordova: cordova plugin add https://git

Alwin jose 1 Oct 23, 2021
iOS photo gallery written in Swift

SwiftPhotoGallery Overview A full screen photo gallery for iOS and tvOS written in Swift. Photos can be panned and zoomed (iOS only) Pinch to zoom (iO

Justin Vallely 271 Dec 17, 2022
Nilay Dagdemir 0 Jan 23, 2022
Photo Gallery App demo using a REST API

Photo Gallery iOS App - (Using Rest API) A demo Photo Gallery App using a Rest API using MVVM architecture in Swift + UIKit. Overview Fully Programmat

Neel Mewada 2 Nov 22, 2021
Photo Browser / Viewer inspired by Facebook's and Tweetbot's with ARC support, swipe-to-dismiss, image progress and more

IDMPhotoBrowser IDMPhotoBrowser is a new implementation based on MWPhotoBrowser. We've added both user experience and technical features inspired by F

Thiago Peres 2.7k Dec 21, 2022
Simple PhotoBrowser/Viewer inspired by facebook, twitter photo browsers written by swift

SKPhotoBrowser [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) Simple PhotoBrowser

keishi suzuki 2.4k Jan 6, 2023
React-native-photo-editor - Photo editor using native modules for iOS and Android

?? Image editor using native modules for iOS and Android. Inherit from 2 available libraries, ZLImageEditor (iOS) and PhotoEditor (Android)

Baron Ha. 244 Jan 5, 2023
DGCropImage - A photo cropping tool which mimics Photo.app written by Swift

DGCropImage A photo cropping tool which mimics Photo.app written by Swift. This

donggyu 11 Jul 14, 2022
Photo-Sharing-App - Photo Sharing App With Swift

Photo Sharing App You can register and log in to this application and share your

Yağız Savran 2 Jun 14, 2022
IRGallery-swift is a powerful gallery for iOS.

IRGallery-swift IRGallery-swift is a powerful gallery for iOS. Features Captions. Rotation support. Load images locally or from a web URL. Custom UITa

Phil Chang 1 Oct 6, 2021
🖼 Gallery App for Actomaton (async/await + Elm Architecture) + SwiftUI.

?? Actomaton-Gallery Gallery App for Actomaton (async/await + Elm Architecture) + SwiftUI. NOTE: Most of the code are reused from Harvest-SwiftUI-Gall

Yasuhiro Inami 44 Dec 20, 2022
Applies filter to a selected image from the Gallery using Combine

CombinePhotoFiltering App CombinePhotoFiltering is an app that applies sepia and bloom to a selected picture from the Photos app. Highlights The app i

Mauricio Esteves 0 Nov 14, 2021
Gallery has a clearer flow based on albums and focuses on the use case of selecting video

Description We all love image pickers, don't we? You may already know of ImagePicker, the all in one solution for capturing pictures and selecting ima

null 1 Sep 14, 2022
Image gallery similar to Adidias' app, built in SwiftUI

TripleStackGallery TripleStackGallery is a image gallery component, which displays a set of images as a stack of three images, always displaying the i

Tomás Martins 5 Aug 29, 2022
An iOS app that helps you check, edit and delete metadata of photos, including but not limited to EXIF, TIFF...

MetaX A simple iOS app that helps you check, edit and delete metadata of photos, including but not limited to EXIF, TIFF... Feature List main metadata

Yuhan Chen 189 Dec 29, 2022