Pick 0.4.3

Pick 0.4.3

TestsTested
LangLanguage SwiftSwift
License MIT
ReleasedLast Release Mar 2018
SPMSupports SPM

Maintained by sgr-ksmt.



Pick 0.4.3

  • By
  • Suguru Kishimoto

Pick

Protocol-Oriented PickerViewController.
You can pick whatever you want from defined data source by you.

GitHub release
Language
Carthage Compatible
CocoaPods
CocoaPodsDL

Feature

  • Can pick single(multiple) item(s).
  • Can use flexible DataSource.
  • Automatic register/dequeue cell inside picker view.
  • Support Pre-fetching.
  • Can customize using options.

How to use

Define Cell

Create Cell that inherit PickableCell.

final class AssetCell: PickableCell {
    private lazy var imageView: UIImageView = {
        let view = UIImageView(frame: .zero)
        view.contentMode = .scaleAspectFill
        view.clipsToBounds = true
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(imageView)
        imageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        imageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private static let fetchOption: PHImageRequestOptions = {
        let options = PHImageRequestOptions()
        options.isSynchronous = true
        options.resizeMode = .exact
        return options
    }()
    
    private var asset: PHAsset?
    func configure(with asset: PHAsset) {
        self.asset = asset
        PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: 300, height: 300), contentMode: .aspectFill, options: type(of: self).fetchOption) { [weak self] (image, _) in
            if self?.asset?.localIdentifier == asset.localIdentifier {
                self?.imageView.image = image
            }
        }
    }
}

NOTE: If you want to use custom cell using xib, add code below.

final class AssetCell: PickableCell {
    override class var registerMode: RegisterMode {
        return .nib(defaultNib)
    }

    // or

    override class var registerMode: RegisterMode {
        return .nib(UINib(nibName: "AssetCell", bundle: nil))
    }
}

Define DataSource

Create DataSource that adapts PickableDataSource.
You have to implement:

  • typealias Cell
  • typealias Item
  • configure(cell: Cell, at indexPath: IndexPath)
  • var numberOfItems: Int
  • pickItems(indexes: [Int]) -> [Item]
final class AssetDataSource: NSObject, PickableDataSource {
    typealias Cell = AssetCell
    typealias Item = PHAsset

    var assets: PHFetchResult<PHAsset>?
    override init() {
        super.init()
        fetchCameraroll()
        PHPhotoLibrary.shared().register(self)
    }

    func fetchCameraroll() {
        guard let cameraroll = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil).firstObject else {
            return
        }
        self.assets = PHAsset.fetchAssets(in: cameraroll, options: nil)
    }

    func configure(cell: Cell, at indexPath: IndexPath) {
        if let asset = assets?.object(at: indexPath.item) {
            cell.configure(with: asset)
        }
    }

    var numberOfItems: Int {
        return assets?.count ?? 0
    }

    func pickItems(indexes: [Int]) -> [Item] {
        return assets?.objects(at: IndexSet(indexes)) ?? []
    }

    deinit {
        PHPhotoLibrary.shared().unregisterChangeObserver(self)
    }
}

extension AssetDataSource: PHPhotoLibraryChangeObserver {
    func photoLibraryDidChange(_ changeInstance: PHChange) {
        DispatchQueue.main.sync { [weak self] in
            guard let `self` = self else {
                return
            }

            guard let assets = self.assets else { return }
            guard let _ = changeInstance.changeDetails(for: assets) else { return }

            self.fetchCameraroll()
            self.notifyUpdate()
        }
    }
}

In order to update picker view after updating datasource, call notifyUpdate()

final class SomeDataSource: NSObject, PickableDataSource {
    private var list: [Int] = []
    func update() {
        list = ...
        notifyUpdate()
    }
}

Setup ViewController

Set data source to PickerViewController(PickerNavigationController).
Also you can customize using PickerOptions.

let nav = PickerNavigationController(dataSource: AssetDataSource())
nav.options = {
    let options = PickerOptions()
    options.limitOfSelection = 3
    options.selectedBorderColor = .red
    options.viewTitle = "Camera Roll"
    return options
}()

nav.pickItemsHandler = { assets in
    print(assets)
}

viewController.present(nav, animated: true, completion: nil)

enjoy 😄

Todo

  • Document comment.

Requirements

  • iOS 10.0+
  • Xcode 9+
  • Swift 4+

Installation

Carthage

  • Add the following to your Cartfile:
github "sgr-ksmt/Pick" ~> 0.3
  • Run carthage update
  • Add the framework as described.

    Details: Carthage Readme

CocoaPods

Pick is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'Pick', '~> 0.3'

and run pod install

Manually Install

Download all *.swift files and put your project.

Change log

Change log is here.

Communication

  • If you found a bug, open an issue.
  • If you have a feature request, open an issue.
  • If you want to contribute, submit a pull request.💪

License

Pick is under MIT license. See the LICENSE file for more info.