Skip to content

tilltue/TLPhotoPicker

Repository files navigation

Version License Platform Swift Sponsor

TLPhotoPicker

A modern, flexible photo and video picker for iOS applications. TLPhotoPicker enables selecting media from multiple smart albums with an interface similar to Facebook's photo picker.

Demo πŸ™‰

Facebook Picker TLPhotoPicker
Facebook Picker TLPhotoPicker

Features

  • βœ… Smart Album Support - Camera roll, selfies, panoramas, favorites, videos, and custom albums
  • πŸ“± Selection Order - Visual order indicators for selected media
  • ▢️ Media Playback - Preview videos and Live Photos directly in the picker
  • ⏱️ Video Duration - Display video length on thumbnails
  • ⚑ High Performance - Async asset loading with excellent scrolling performance
  • 🎨 Customizable - Custom cells, selection rules, and UI elements
  • πŸ”„ Live Updates - Automatic reload when Photos library changes
  • ☁️ iCloud Support - Seamless iCloud Photo Library integration
Smart Albums Live Photo Video Photo Custom Cell
Smart Album LivePhoto Video Photo Custom

Custom Camera Cell

Live Camera Cell
Camera Cell

Requirements

  • iOS 13.0+
  • Swift 5.0+
  • Xcode 14.0+

Installation

CocoaPods

platform :ios, '13.0'
pod "TLPhotoPicker"

Swift Package Manager

Add TLPhotoPicker as a dependency in your Package.swift:

dependencies: [
    .package(url: "https://github.com/tilltue/TLPhotoPicker.git", .upToNextMajor(from: "2.1.0"))
]

Privacy Configuration

Add the following keys to your Info.plist:

<key>NSPhotoLibraryUsageDescription</key>
<string>Access to photos is required to select images</string>
<key>NSCameraUsageDescription</key>
<string>Camera access is required to take photos</string>

iOS 14+ Limited Photo Access

To suppress automatic prompting, add this to Info.plist:

<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<true/>

Learn more

Quick Start

Basic Usage

import TLPhotoPicker

class ViewController: UIViewController {
    @IBAction func openPhotoPicker() {
        let picker = TLPhotosPickerViewController()
        picker.delegate = self
        present(picker, animated: true)
    }
}

extension ViewController: TLPhotosPickerViewControllerDelegate {
    func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) {
        // Handle selected assets
        for asset in withTLPHAssets {
            print("Selected: \(asset.originalFileName ?? "Unknown")")
        }
    }
}

Modern Async/Await (iOS 13+)

// Load images asynchronously
Task {
    if let image = await selectedAssets.first?.fullResolutionImage() {
        await MainActor.run {
            self.imageView.image = image
        }
    }
}

// Load multiple images concurrently
Task {
    let images = await withTaskGroup(of: UIImage?.self) { group in
        for asset in selectedAssets {
            group.addTask { await asset.fullResolutionImage() }
        }

        var results: [UIImage] = []
        for await image in group {
            if let image = image { results.append(image) }
        }
        return results
    }

    await MainActor.run {
        self.displayImages(images)
    }
}

Configuration with Builder Pattern

let picker = TLPhotosPickerViewController()

// Use presets
picker.configure = .singlePhoto
picker.configure = .videoOnly
picker.configure = .compactGrid

// Or build custom configuration
picker.configure = TLPhotosPickerConfigure()
    .numberOfColumns(3)
    .maxSelection(20)
    .allowVideo(true)
    .allowLivePhotos(true)
    .selectedColor(.systemPink)
    .useCameraButton(true)

// Extend presets
picker.configure = .videoOnly
    .numberOfColumns(4)
    .selectedColor(.systemBlue)

present(picker, animated: true)

Documentation

For detailed information, see:

Common Use Cases

Single Photo Selection

picker.configure = .singlePhoto
    .selectedColor(.systemPurple)

Video Recording Only

picker.configure = TLPhotosPickerConfigure()
    .mediaType(.video)
    .allowPhotograph(false)
    .allowVideoRecording(true)

Instagram-style Grid

picker.configure = .compactGrid
    .maxSelection(10)
    .selectedColor(UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0))

Custom Selection Rules

picker.canSelectAsset = { asset in
    // Only allow images larger than 300x300
    return asset.pixelWidth >= 300 && asset.pixelHeight >= 300
}

picker.didExceedMaximumNumberOfSelection = { picker in
    // Show alert when limit reached
}

Delegate Methods

protocol TLPhotosPickerViewControllerDelegate {
    func shouldDismissPhotoPicker(withTLPHAssets: [TLPHAsset]) -> Bool
    func dismissPhotoPicker(withTLPHAssets: [TLPHAsset])
    func dismissPhotoPicker(withPHAssets: [PHAsset])
    func photoPickerDidCancel()
    func dismissComplete()
    func canSelectAsset(phAsset: PHAsset) -> Bool
    func didExceedMaximumNumberOfSelection(picker: TLPhotosPickerViewController)
    func handleNoAlbumPermissions(picker: TLPhotosPickerViewController)
    func handleNoCameraPermissions(picker: TLPhotosPickerViewController)
}

TLPHAsset

The library provides TLPHAsset, a wrapper around PHAsset with convenient helper methods:

public struct TLPHAsset {
    public var phAsset: PHAsset?
    public var selectedOrder: Int
    public var type: AssetType // .photo, .video, .livePhoto
    public var originalFileName: String?
    public var isSelectedFromCamera: Bool

    // Async image loading
    public func fullResolutionImage() async -> UIImage?

    // iCloud download
    public func cloudImageDownload(
        progressBlock: @escaping (Double) -> Void,
        completionBlock: @escaping (UIImage?) -> Void
    ) -> PHImageRequestID?

    // Export to file
    public func tempCopyMediaFile(
        convertLivePhotosToJPG: Bool = false,
        progressBlock: ((Double) -> Void)? = nil,
        completionBlock: @escaping ((URL, String) -> Void)
    ) -> PHImageRequestID?

    // File size
    public func photoSize(completion: @escaping (Int) -> Void)
    public func videoSize(completion: @escaping (Int) -> Void)

    // Static method
    public static func asset(with localIdentifier: String) -> TLPHAsset?
}

See API Reference for complete documentation.

Contributing

Issues and pull requests are welcome! Please check existing issues before creating new ones.

πŸ’– Support This Project

TLPhotoPicker is an open-source project maintained in my free time. If you find it useful, please consider supporting its development:

GitHub Sponsors

Your support helps me:

  • πŸ› Fix bugs and maintain compatibility with latest iOS versions
  • ✨ Develop new features and improvements
  • πŸ“š Improve documentation and examples
  • ⚑ Performance optimizations and code quality

Every contribution is appreciated! πŸ™

Author

wade.hawk - [email protected]

Does your organization use TLPhotoPicker? Let me know!

License

TLPhotoPicker is available under the MIT license. See the LICENSE file for details.

About

πŸ“· multiple phassets picker for iOS lib. like a facebook

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors 40

Languages