Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Ability of multiple selection on PhotoLibraryViewController #256

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions ALCameraViewController/Utilities/ImageFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,20 @@ public class ImageFetcher {
}
}
}

public static func resolveAssets(_ assets: [PHAsset], size: CGSize = CGSize(width: 720, height: 1280)) -> [UIImage] {
let imageManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true

var images = [UIImage]()
for asset in assets {
imageManager.requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: requestOptions) { image, _ in
if let image = image {
images.append(image)
}
}
}
return images
}
}
14 changes: 14 additions & 0 deletions ALCameraViewController/ViewController/CameraViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ public extension CameraViewController {

return navigationController
}

/// Provides an multiple image picker wrapped inside a UINavigationController instance
public class func imagePickerViewController(completion: @escaping PhotoLibraryViewMultipleSelectionComplete) -> UINavigationController {
let imagePicker = PhotoLibraryViewController()
imagePicker.allowsMultipleSelection = true
imagePicker.onMultipleSelectionComplete = completion

let navigationController = UINavigationController(rootViewController: imagePicker)
navigationController.navigationBar.barTintColor = UIColor.black
navigationController.navigationBar.barStyle = UIBarStyle.black
navigationController.modalTransitionStyle = UIModalTransitionStyle.crossDissolve

return navigationController
}
}

open class CameraViewController: UIViewController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@ internal let ImageCellIdentifier = "ImageCell"
internal let defaultItemSpacing: CGFloat = 1

public typealias PhotoLibraryViewSelectionComplete = (PHAsset?) -> Void
public typealias PhotoLibraryViewMultipleSelectionComplete = ([PHAsset]?) -> Void

public class PhotoLibraryViewController: UIViewController {

internal var assets: PHFetchResult<PHAsset>? = nil

/// Controls whether multiple cells can be selected, default is `false`.
public var allowsMultipleSelection = false
public var onSelectionComplete: PhotoLibraryViewSelectionComplete?
public var onMultipleSelectionComplete: PhotoLibraryViewMultipleSelectionComplete?

private lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
Expand All @@ -32,6 +36,7 @@ public class PhotoLibraryViewController: UIViewController {
let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = UIColor.clear
collectionView.allowsMultipleSelection = self.allowsMultipleSelection
return collectionView
}()

Expand All @@ -47,6 +52,12 @@ public class PhotoLibraryViewController: UIViewController {
target: self,
action: #selector(dismissLibrary))

if allowsMultipleSelection {
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done,
target: self,
action: #selector(selectMultiple))
}

view.backgroundColor = UIColor(white: 0.2, alpha: 1)
view.addSubview(collectionView)

Expand All @@ -73,7 +84,12 @@ public class PhotoLibraryViewController: UIViewController {
}

@objc public func dismissLibrary() {
onSelectionComplete?(nil)
allowsMultipleSelection ? onMultipleSelectionComplete?(nil) : onSelectionComplete?(nil)
}

@objc public func selectMultiple() {
let assets: [PHAsset]? = collectionView.indexPathsForSelectedItems?.flatMap { self.itemAtIndexPath($0) }
onMultipleSelectionComplete?(assets)
}

private func onSuccess(_ photos: PHFetchResult<PHAsset>) {
Expand Down Expand Up @@ -122,6 +138,23 @@ extension PhotoLibraryViewController : UICollectionViewDataSource {
// MARK: - UICollectionViewDelegate -
extension PhotoLibraryViewController : UICollectionViewDelegateFlowLayout {
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard !allowsMultipleSelection else {
return
}
onSelectionComplete?(itemAtIndexPath(indexPath))
}

public func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
guard allowsMultipleSelection else {
return true
}

if let selectedItems = collectionView.indexPathsForSelectedItems {
if selectedItems.contains(indexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
return false
}
}
return true
}
}
7 changes: 7 additions & 0 deletions ALCameraViewController/Views/ImageCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ class ImageCell: UICollectionViewCell {
compatibleWith: nil)
}

override var isSelected: Bool {
didSet {
contentView.layer.borderWidth = 2.0
contentView.layer.borderColor = isSelected ? UIColor.blue.cgColor : UIColor.clear.cgColor
}
}

func configureWithModel(_ model: PHAsset) {

if tag != 0 {
Expand Down
24 changes: 18 additions & 6 deletions Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var croppingParametersView: UIView!
@IBOutlet weak var minimumSizeLabel: UILabel!

@IBOutlet weak var multipleSelectionSwitch: UISwitch!

override func viewDidLoad() {
super.viewDidLoad()

Expand All @@ -40,12 +41,23 @@ class ViewController: UIViewController {
}

@IBAction func openLibrary(_ sender: Any) {
let libraryViewController = CameraViewController.imagePickerViewController(croppingParameters: croppingParameters) { [weak self] image, asset in
self?.imageView.image = image
self?.dismiss(animated: true, completion: nil)
if multipleSelectionSwitch.isOn {
let libraryViewController = CameraViewController.imagePickerViewController(completion: { [weak self] assets in
if let assets = assets {
let images = ImageFetcher.resolveAssets(assets, size: largestPhotoSize())
self?.imageView.image = images.last
}
self?.dismiss(animated: true, completion: nil)
})
present(libraryViewController, animated: true, completion: nil)
} else {
let libraryViewController = CameraViewController.imagePickerViewController(croppingParameters: croppingParameters) {
[weak self] image, asset in
self?.imageView.image = image
self?.dismiss(animated: true, completion: nil)
}
present(libraryViewController, animated: true, completion: nil)
}

present(libraryViewController, animated: true, completion: nil)
}

@IBAction func libraryChanged(_ sender: Any) {
Expand Down
36 changes: 25 additions & 11 deletions Example/ViewController.xib
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_0" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand All @@ -20,6 +20,7 @@
<outlet property="croppingParametersView" destination="aZk-39-lei" id="iih-He-zYC"/>
<outlet property="imageView" destination="I4G-in-XtY" id="U1I-c7-fHk"/>
<outlet property="minimumSizeLabel" destination="DXi-q2-e5s" id="NxY-Mc-zZv"/>
<outlet property="multipleSelectionSwitch" destination="gVG-zP-Dbh" id="oTo-4p-JDL"/>
<outlet property="view" destination="iN0-l3-epB" id="NQI-AD-Uhb"/>
</connections>
</placeholder>
Expand All @@ -28,11 +29,8 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="I4G-in-XtY">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QHP-Db-zQM">
<rect key="frame" x="0.0" y="0.0" width="320" height="118"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="177"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cgD-PF-WNE">
<rect key="frame" x="70" y="48" width="41" height="29"/>
Expand All @@ -45,7 +43,7 @@
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Cropping" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3e8-yb-h3L">
<rect key="frame" x="258" y="85" width="53.5" height="17"/>
<rect key="frame" x="258" y="85" width="54" height="17"/>
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
Expand All @@ -61,7 +59,7 @@
</connections>
</button>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="kvv-7d-Re7">
<rect key="frame" x="260.5" y="48" width="51" height="31"/>
<rect key="frame" x="261" y="48" width="51" height="31"/>
<connections>
<action selector="croppingChanged:" destination="-1" eventType="valueChanged" id="fjU-Hs-bwf"/>
</connections>
Expand All @@ -73,7 +71,16 @@
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Library Access" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VFc-CF-Vtc">
<rect key="frame" x="158" y="85" width="84.5" height="17"/>
<rect key="frame" x="158" y="85" width="85" height="17"/>
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="gVG-zP-Dbh">
<rect key="frame" x="176" y="110" width="51" height="31"/>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Multiple Selection" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Bq-QY-3gS">
<rect key="frame" x="148" y="148" width="105" height="17"/>
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
Expand All @@ -82,12 +89,16 @@
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.29999999999999999" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="kvv-7d-Re7" firstAttribute="centerX" secondItem="3e8-yb-h3L" secondAttribute="centerX" id="03O-8V-75Q"/>
<constraint firstItem="5Bq-QY-3gS" firstAttribute="centerX" secondItem="gVG-zP-Dbh" secondAttribute="centerX" id="1fg-i4-G4k"/>
<constraint firstItem="3e8-yb-h3L" firstAttribute="leading" secondItem="VFc-CF-Vtc" secondAttribute="trailing" constant="15.5" id="4Jt-tB-SUL"/>
<constraint firstAttribute="bottom" secondItem="3e8-yb-h3L" secondAttribute="bottom" constant="16" id="5p4-dS-pea"/>
<constraint firstAttribute="bottom" secondItem="3e8-yb-h3L" secondAttribute="bottom" constant="75" id="5p4-dS-pea"/>
<constraint firstItem="VFc-CF-Vtc" firstAttribute="top" secondItem="JPj-mG-Hu1" secondAttribute="bottom" constant="6" id="6Pj-pH-zeh"/>
<constraint firstItem="JPj-mG-Hu1" firstAttribute="top" secondItem="kvv-7d-Re7" secondAttribute="top" id="7aB-or-fz9"/>
<constraint firstItem="JPj-mG-Hu1" firstAttribute="centerX" secondItem="VFc-CF-Vtc" secondAttribute="centerX" id="9gI-Mi-9w4"/>
<constraint firstItem="gVG-zP-Dbh" firstAttribute="top" secondItem="VFc-CF-Vtc" secondAttribute="bottom" constant="8" symbolic="YES" id="Ko5-KT-AwX"/>
<constraint firstItem="3e8-yb-h3L" firstAttribute="top" secondItem="kvv-7d-Re7" secondAttribute="bottom" constant="6" id="SdV-Ft-rmy"/>
<constraint firstItem="gVG-zP-Dbh" firstAttribute="trailing" secondItem="JPj-mG-Hu1" secondAttribute="trailing" id="UQx-B3-kh2"/>
<constraint firstItem="5Bq-QY-3gS" firstAttribute="top" secondItem="gVG-zP-Dbh" secondAttribute="bottom" constant="7" id="Wjn-jU-jjU"/>
<constraint firstAttribute="trailing" secondItem="3e8-yb-h3L" secondAttribute="trailing" constant="8.5" id="ZKC-Ah-kcn"/>
<constraint firstItem="kvv-7d-Re7" firstAttribute="top" secondItem="YHP-W6-S2W" secondAttribute="top" id="bj8-Oa-dOs"/>
<constraint firstItem="cgD-PF-WNE" firstAttribute="centerY" secondItem="YHP-W6-S2W" secondAttribute="centerY" id="cYp-Ej-9Ae"/>
Expand Down Expand Up @@ -121,7 +132,7 @@
</connections>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Minimum size: 60" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DXi-q2-e5s">
<rect key="frame" x="185" y="64" width="105.5" height="17"/>
<rect key="frame" x="184" y="64" width="106" height="17"/>
<fontDescription key="fontDescription" name="AppleSDGothicNeo-Regular" family="Apple SD Gothic Neo" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
Expand Down Expand Up @@ -166,6 +177,9 @@
<constraint firstItem="k5h-ry-m8S" firstAttribute="centerX" secondItem="In7-Or-H5s" secondAttribute="centerX" id="z4S-xt-ZNI"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="I4G-in-XtY">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
Expand Down