diff --git a/Example/INSPhotoGallery.xcodeproj/project.pbxproj b/Example/INSPhotoGallery.xcodeproj/project.pbxproj index e5261b5..4ccb4b0 100644 --- a/Example/INSPhotoGallery.xcodeproj/project.pbxproj +++ b/Example/INSPhotoGallery.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ D2EF36201CB299CF00033131 /* CustomOverlayView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D2EF361F1CB299CF00033131 /* CustomOverlayView.xib */; }; D2EF36221CB29C6600033131 /* CustomPhotoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EF36211CB29C6600033131 /* CustomPhotoModel.swift */; }; D2EF36241CB2A67800033131 /* CustomModelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EF36231CB2A67800033131 /* CustomModelViewController.swift */; }; + D93AB2C224A558F200BB885A /* INSConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93AB2C124A558F100BB885A /* INSConfiguration.swift */; }; FB44620B1AE393EEB9BC3649 /* Pods_INSPhotoGallery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 043F1D6415A9A5BC7A90DF71 /* Pods_INSPhotoGallery.framework */; }; /* End PBXBuildFile section */ @@ -89,6 +90,7 @@ D2EF361F1CB299CF00033131 /* CustomOverlayView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CustomOverlayView.xib; sourceTree = ""; }; D2EF36211CB29C6600033131 /* CustomPhotoModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPhotoModel.swift; sourceTree = ""; }; D2EF36231CB2A67800033131 /* CustomModelViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomModelViewController.swift; sourceTree = ""; }; + D93AB2C124A558F100BB885A /* INSConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = INSConfiguration.swift; path = ../INSPhotoGallery/INSConfiguration.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -151,6 +153,7 @@ D2EF35E81CB288F300033131 = { isa = PBXGroup; children = ( + D93AB2C124A558F100BB885A /* INSConfiguration.swift */, D2EF35F31CB288F300033131 /* INSPhotoGallery */, 642427271CDE10750037E8DA /* INSPhotoGalleryFramework */, D2EF35F21CB288F300033131 /* Products */, @@ -355,6 +358,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D93AB2C224A558F200BB885A /* INSConfiguration.swift in Sources */, 642427431CDE10970037E8DA /* INSPhotosViewController.swift in Sources */, 642427401CDE10970037E8DA /* INSPhotosInteractionAnimator.swift in Sources */, 642427421CDE10970037E8DA /* INSPhotosTransitionAnimator.swift in Sources */, diff --git a/Example/INSPhotoGallery/ViewController.swift b/Example/INSPhotoGallery/ViewController.swift index 8e9d4e1..a6bbc33 100644 --- a/Example/INSPhotoGallery/ViewController.swift +++ b/Example/INSPhotoGallery/ViewController.swift @@ -57,7 +57,16 @@ extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFl func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { let cell = collectionView.cellForItem(at: indexPath) as! ExampleCollectionViewCell let currentPhoto = photos[(indexPath as NSIndexPath).row] - let galleryPreview = INSPhotosViewController(photos: photos, initialPhoto: currentPhoto, referenceView: cell) + + let configuration = INSConfiguration() + configuration.backgroundColor = .white + configuration.activityIndicatorColor = .blue + configuration.shadowHidden = true + configuration.rightBarButtonHidden = true + configuration.leftBarButtonHidden = true + configuration.navigationTitleTextColor = .green + + let galleryPreview = INSPhotosViewController(photos: photos, initialPhoto: currentPhoto, configuration: configuration) if useCustomOverlay { galleryPreview.overlayView = CustomOverlayView(frame: CGRect.zero) } diff --git a/INSPhotoGallery.xcodeproj/project.pbxproj b/INSPhotoGallery.xcodeproj/project.pbxproj index c105180..cf91b36 100644 --- a/INSPhotoGallery.xcodeproj/project.pbxproj +++ b/INSPhotoGallery.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ C9E5C3992141324800B0694E /* INSPhotoGallery.bundle in Resources */ = {isa = PBXBuildFile; fileRef = C9E5C38F2141324800B0694E /* INSPhotoGallery.bundle */; }; C9E5C39A2141324800B0694E /* INSPhotosInteractionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E5C3902141324800B0694E /* INSPhotosInteractionAnimator.swift */; }; C9E5C39B2141324800B0694E /* INSPhotoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E5C3912141324800B0694E /* INSPhotoViewController.swift */; }; + D93AB2C024A543F300BB885A /* INSConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93AB2BF24A543F300BB885A /* INSConfiguration.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -34,6 +35,7 @@ C9E5C38F2141324800B0694E /* INSPhotoGallery.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = INSPhotoGallery.bundle; sourceTree = ""; }; C9E5C3902141324800B0694E /* INSPhotosInteractionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = INSPhotosInteractionAnimator.swift; sourceTree = ""; }; C9E5C3912141324800B0694E /* INSPhotoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = INSPhotoViewController.swift; sourceTree = ""; }; + D93AB2BF24A543F300BB885A /* INSConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = INSConfiguration.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,6 +74,7 @@ C9E5C3902141324800B0694E /* INSPhotosInteractionAnimator.swift */, C9E5C3882141324800B0694E /* INSPhotosOverlayView.swift */, C9E5C38E2141324800B0694E /* INSPhotosTransitionAnimator.swift */, + D93AB2BF24A543F300BB885A /* INSConfiguration.swift */, C9E5C3892141324800B0694E /* INSPhotosViewController.swift */, C9E5C3912141324800B0694E /* INSPhotoViewController.swift */, C9E5C38C2141324800B0694E /* INSScalingImageView.swift */, @@ -166,6 +169,7 @@ C9E5C3952141324800B0694E /* UIVIew+INSPhotoViewer.swift in Sources */, C9E5C3982141324800B0694E /* INSPhotosTransitionAnimator.swift in Sources */, C9E5C3972141324800B0694E /* INSPhoto.swift in Sources */, + D93AB2C024A543F300BB885A /* INSConfiguration.swift in Sources */, C9E5C39B2141324800B0694E /* INSPhotoViewController.swift in Sources */, C9E5C39A2141324800B0694E /* INSPhotosInteractionAnimator.swift in Sources */, C9E5C3932141324800B0694E /* INSPhotosViewController.swift in Sources */, diff --git a/INSPhotoGallery/INSConfiguration.swift b/INSPhotoGallery/INSConfiguration.swift new file mode 100644 index 0000000..28380ea --- /dev/null +++ b/INSPhotoGallery/INSConfiguration.swift @@ -0,0 +1,54 @@ +// +// INSConfiguration.swift +// INSPhotoGallery +// +// Created by Danil Blinov on 25.06.2020. +// Copyright © 2020 Inspace. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this library except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +import UIKit + +public class INSConfiguration: NSObject { + /* + * Specify backgroundColor for INSScalingImageView + */ + open var backgroundColor: UIColor = .black + + /* + * Specify backgroundColor for INSScalingImageView .imageView + */ + open var imageViewBackgroundColor: UIColor = .clear + /* + + * Specify color for UIActivityIndicatorView + */ + open var activityIndicatorColor: UIColor = .white + + /* + * Specify color for UIActivityIndicatorView + */ + open var navigationTitleTextColor: UIColor = .white + + /* + * Specify parameters for INSPhotosOverlayViewable + */ + open var shadowStartColor: UIColor = UIColor.black.withAlphaComponent(0.5) + open var shadowEndColor: UIColor = UIColor.clear + open var shadowHidden: Bool = false + + open var rightBarButtonHidden: Bool = false + open var leftBarButtonHidden: Bool = false + +} diff --git a/INSPhotoGallery/INSPhotoViewController.swift b/INSPhotoGallery/INSPhotoViewController.swift index 3a25351..0b46a1f 100644 --- a/INSPhotoGallery/INSPhotoViewController.swift +++ b/INSPhotoGallery/INSPhotoViewController.swift @@ -21,6 +21,7 @@ import UIKit open class INSPhotoViewController: UIViewController, UIScrollViewDelegate { var photo: INSPhotoViewable + let configuration: INSConfiguration var longPressGestureHandler: ((UILongPressGestureRecognizer) -> ())? @@ -45,8 +46,9 @@ open class INSPhotoViewController: UIViewController, UIScrollViewDelegate { return activityIndicator }() - public init(photo: INSPhotoViewable) { + public init(photo: INSPhotoViewable, configuration: INSConfiguration) { self.photo = photo + self.configuration = configuration super.init(nibName: nil, bundle: nil) } @@ -64,8 +66,10 @@ open class INSPhotoViewController: UIViewController, UIScrollViewDelegate { scalingImageView.delegate = self scalingImageView.frame = view.bounds scalingImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + scalingImageView.imageView.backgroundColor = configuration.imageViewBackgroundColor view.addSubview(scalingImageView) + activityIndicator.color = configuration.activityIndicatorColor view.addSubview(activityIndicator) activityIndicator.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY) activityIndicator.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin] diff --git a/INSPhotoGallery/INSPhotosOverlayView.swift b/INSPhotoGallery/INSPhotosOverlayView.swift index a8a6dfe..45b7d60 100644 --- a/INSPhotoGallery/INSPhotosOverlayView.swift +++ b/INSPhotoGallery/INSPhotosOverlayView.swift @@ -21,7 +21,7 @@ import UIKit public protocol INSPhotosOverlayViewable:class { var photosViewController: INSPhotosViewController? { get set } - + func populateWithPhoto(_ photo: INSPhotoViewable) func setHidden(_ hidden: Bool, animated: Bool) func view() -> UIView @@ -40,6 +40,8 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { open private(set) var navigationItem: UINavigationItem! open weak var photosViewController: INSPhotosViewController? + var configuration: INSConfiguration! + private var currentPhoto: INSPhotoViewable? private var topShadow: CAGradientLayer! @@ -50,6 +52,7 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { navigationItem.leftBarButtonItem = leftBarButtonItem } } + open var rightBarButtonItem: UIBarButtonItem? { didSet { navigationItem.rightBarButtonItem = rightBarButtonItem @@ -68,9 +71,11 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { navigationBar.titleTextAttributes = titleTextAttributes } } + #endif - public override init(frame: CGRect) { + init(frame: CGRect, configuration: INSConfiguration) { + self.configuration = configuration super.init(frame: frame) setupShadows() setupNavigationBar() @@ -176,14 +181,18 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { let horizontalPositionConstraint = NSLayoutConstraint(item: navigationBar!, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: 0.0) self.addConstraints([topConstraint,widthConstraint,horizontalPositionConstraint]) + + if !configuration.rightBarButtonHidden { + rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(INSPhotosOverlayView.actionButtonTapped(_:))) + } + + if configuration.leftBarButtonHidden { return } if let bundlePath = Bundle(for: type(of: self)).path(forResource: "INSPhotoGallery", ofType: "bundle") { let bundle = Bundle(path: bundlePath) leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "INSPhotoGalleryClose", in: bundle, compatibleWith: nil), landscapeImagePhone: UIImage(named: "INSPhotoGalleryCloseLandscape", in: bundle, compatibleWith: nil), style: .plain, target: self, action: #selector(INSPhotosOverlayView.closeButtonTapped(_:))) } else { leftBarButtonItem = UIBarButtonItem(title: "CLOSE".uppercased(), style: .plain, target: self, action: #selector(INSPhotosOverlayView.closeButtonTapped(_:))) } - - rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(INSPhotosOverlayView.actionButtonTapped(_:))) } @@ -192,6 +201,7 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { captionLabel = UILabel() captionLabel.translatesAutoresizingMaskIntoConstraints = false captionLabel.backgroundColor = UIColor.clear + captionLabel.textColor = configuration.navigationTitleTextColor captionLabel.numberOfLines = 0 addSubview(captionLabel) @@ -202,8 +212,8 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { } private func setupShadows() { - let startColor = UIColor.black.withAlphaComponent(0.5) - let endColor = UIColor.clear + let startColor = configuration.shadowStartColor + let endColor = configuration.shadowEndColor self.topShadow = CAGradientLayer() topShadow.colors = [startColor.cgColor, endColor.cgColor] @@ -213,6 +223,9 @@ open class INSPhotosOverlayView: UIView , INSPhotosOverlayViewable { bottomShadow.colors = [endColor.cgColor, startColor.cgColor] self.layer.insertSublayer(bottomShadow, at: 0) + topShadow.isHidden = configuration.shadowHidden + bottomShadow.isHidden = configuration.shadowHidden + self.updateShadowFrames() } diff --git a/INSPhotoGallery/INSPhotosViewController.swift b/INSPhotoGallery/INSPhotosViewController.swift index ca72394..1b414ef 100644 --- a/INSPhotoGallery/INSPhotosViewController.swift +++ b/INSPhotoGallery/INSPhotosViewController.swift @@ -61,7 +61,7 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo /* * The overlay view displayed over photos, can be changed but must implement INSPhotosOverlayViewable */ - open var overlayView: INSPhotosOverlayViewable = INSPhotosOverlayView(frame: CGRect.zero) { + open var overlayView: INSPhotosOverlayViewable { willSet { overlayView.view().removeFromSuperview() } @@ -72,10 +72,10 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo view.addSubview(overlayView.view()) } } - + /* - * Whether or not we should confirm with the user before deleting a photo - */ + * Whether or not we should confirm with the user before deleting a photo + */ open var shouldConfirmDeletion: Bool = false /* @@ -91,9 +91,9 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo open var currentPhoto: INSPhotoViewable? { return currentPhotoViewController?.photo } - + /* - * maximum zoom scale for the photos. Default is 1.0 + * Maximum zoom scale for the photos. Default is 1.0 */ open var maximumZoomScale: CGFloat = 1.0 { didSet { @@ -105,6 +105,7 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo public private(set) var pageViewController: UIPageViewController! public private(set) var dataSource: INSPhotosDataSource + let configuration: INSConfiguration public let interactiveAnimator: INSPhotosInteractionAnimator = INSPhotosInteractionAnimator() public let transitionAnimator: INSPhotosTransitionAnimator = INSPhotosTransitionAnimator() @@ -142,12 +143,16 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo required public init?(coder aDecoder: NSCoder) { dataSource = INSPhotosDataSource(photos: []) + configuration = INSConfiguration() + overlayView = INSPhotosOverlayView(frame: CGRect.zero, configuration: configuration) super.init(nibName: nil, bundle: nil) initialSetupWithInitialPhoto(nil) } public override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: Bundle!) { dataSource = INSPhotosDataSource(photos: []) + configuration = INSConfiguration() + overlayView = INSPhotosOverlayView(frame: CGRect.zero, configuration: configuration) super.init(nibName: nil, bundle: nil) initialSetupWithInitialPhoto(nil) } @@ -161,8 +166,10 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo - returns: A fully initialized object. */ - public init(photos: [INSPhotoViewable], initialPhoto: INSPhotoViewable? = nil, referenceView: UIView? = nil) { - dataSource = INSPhotosDataSource(photos: photos) + public init(photos: [INSPhotoViewable], initialPhoto: INSPhotoViewable? = nil, referenceView: UIView? = nil, configuration: INSConfiguration = INSConfiguration()) { + self.dataSource = INSPhotosDataSource(photos: photos) + self.configuration = configuration + self.overlayView = INSPhotosOverlayView(frame: CGRect.zero, configuration: configuration) super.init(nibName: nil, bundle: nil) initialSetupWithInitialPhoto(initialPhoto) transitionAnimator.startingView = referenceView @@ -181,7 +188,7 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo } private func setupOverlayViewInitialItems() { - let textColor = view.tintColor ?? UIColor.white + let textColor = configuration.navigationTitleTextColor if let overlayView = overlayView as? INSPhotosOverlayView { overlayView.photosViewController = self #if swift(>=4.0) @@ -224,7 +231,6 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo } private func setupOverlayView() { - overlayView.view().autoresizingMask = [.flexibleWidth, .flexibleHeight] overlayView.view().frame = view.bounds view.addSubview(overlayView.view()) @@ -373,7 +379,7 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo // MARK: - UIPageViewControllerDataSource / UIPageViewControllerDelegate public func initializePhotoViewControllerForPhoto(_ photo: INSPhotoViewable) -> INSPhotoViewController { - let photoViewController = INSPhotoViewController(photo: photo) + let photoViewController = INSPhotoViewController(photo: photo, configuration: configuration) singleTapGestureRecognizer.require(toFail: photoViewController.doubleTapGestureRecognizer) photoViewController.longPressGestureHandler = { [weak self] gesture in guard let weakSelf = self else { @@ -398,6 +404,7 @@ open class INSPhotosViewController: UIViewController, UIPageViewControllerDataSo } } photoViewController.scalingImageView.maximumZoomScale = self.maximumZoomScale + photoViewController.scalingImageView.backgroundColor = configuration.backgroundColor return photoViewController } diff --git a/README.md b/README.md index 2770786..ef9059e 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,35 @@ func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath i } ``` +# UI Configuration + + +```swift +func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { + let cell = collectionView.cellForItemAtIndexPath(indexPath) as! ExampleCollectionViewCell + let currentPhoto = photos[indexPath.row] + + let configuration = INSConfiguration() + configuration.backgroundColor = .white + configuration.activityIndicatorColor = .blue + configuration.shadowHidden = true + configuration.rightBarButtonHidden = true + configuration.leftBarButtonHidden = true + configuration.navigationTitleTextColor = .green + + let galleryPreview = INSPhotosViewController(photos: photos, initialPhoto: currentPhoto, referenceView: cell, configuration: configuration) + + galleryPreview.referenceViewForPhotoWhenDismissingHandler = { [weak self] photo in + if let index = self?.photos.indexOf({$0 === photo}) { + let indexPath = NSIndexPath(forItem: index, inSection: 0) + return collectionView.cellForItemAtIndexPath(indexPath) as? ExampleCollectionViewCell + } + return nil + } + presentViewController(galleryPreview, animated: true, completion: nil) +} +``` + # Custom Photo Model You are able to create your custom photo model which can be use instead default `INSPhoto`. Default implementation don't cache images. If you would like to use some caching mechanism or use some library for downloading images for example `HanekeSwift` use must implement `INSPhotoViewable` protocol.