SkillAgentSearch skills...

HXPhotoPicker

图片/视频选择器 - 支持LivePhoto、GIF图片选择、3DTouch预览、在线下载iCloud上的资源、编辑图片/视频、浏览网络图片 功能 Imitation wx photo/image picker - support for LivePhoto, GIF image selection, 3DTouch preview, Download the resources on iCloud online, browse the web image function

Install / Use

/learn @SilenceLove/HXPhotoPicker

README

<h4 align="right">中文 | <strong><a href="https://github.com/SilenceLove/HXPhotoPicker/blob/master/Documentation/README_EN.md">English</a></strong></h4> <p align="center"> <a><img src="https://github.com/SilenceLove/PictureMaterial/blob/main/HXPhotoPicker/README/sample_graph.png?raw=true" width = "384" height = "292.65" ></a> </p> <p align="center"> <a href="https://github.com/SilenceLove/HXPhotoPicker"><img src="https://travis-ci.org/SilenceLove/HXPhotoPicker.svg?branch=master"></a> <a href="https://github.com/SilenceLove/HXPhotoPicker"><img src="https://badgen.net/badge/icon/iOS%2010.0%2B?color=cyan&icon=apple&label"></a> <a href="https://github.com/SilenceLove/HXPhotoPicker"><img src="http://img.shields.io/cocoapods/v/HXPhotoPicker.svg?logo=cocoapods&logoColor=ffffff"></a> <a href="https://developer.apple.com/Swift"><img src="http://img.shields.io/badge/language-Swift-orange.svg?logo=common-workflow-language"></a> <a href="http://mit-license.org"><img src="http://img.shields.io/badge/license-MIT-333333.svg?logo=letterboxd&logoColor=ffffff"></a> <div align="center">一款图片/视频选择器-支持LivePhoto、GIF选择、iCloud/网络资源在线下载、图片/视频编辑</div> </p>

目录

<a id="功能"></a> 功能

  • [x] UI 外观支持浅色/深色/自动/自定义
  • [x] 支持多选/混合内容选择
  • [x] 支持的媒体类型:
    • [x] Photo
    • [x] GIF
    • [x] Live Photo
    • [x] Video
  • [x] 支持的本地资源类型:
    • [x] Photo
    • [x] Video
    • [x] GIF
    • [x] Live Photo
  • [x] 支持的网络资源类型:
    • [x] Photo
    • [x] Video
  • [x] 支持下载iCloud上的资源
  • [x] 支持手势返回
  • [x] 支持滑动选择
  • [x] 编辑图片(支持动图、网络资源)
    • [x] 涂鸦
    • [x] 贴纸
    • [x] 文字
    • [x] 裁剪
    • [x] 旋转任意角度
    • [x] 自定义蒙版
    • [x] 马赛克
    • [x] 画面调整
    • [x] 滤镜
  • [x] 编辑视频(支持网络资源)
    • [x] 涂鸦
    • [x] 贴纸(支持GIF)
    • [x] 文字
    • [x] 配乐(支持歌词字幕)
    • [x] 裁剪时长
    • [x] 裁剪尺寸
    • [x] 旋转任意角度
    • [x] 自定义蒙版
    • [x] 画面调整
    • [x] 滤镜
  • [x] 相册展现方式
    • [x] 单独列表
    • [x] 弹窗
  • [x] 多平台支持
    • [x] iOS
    • [x] iPadOS
    • [x] Mac Catalyst
  • [x] 国际化支持
    • [x] 🇨🇳 简体中文 (zh-Hans)
    • [x] 🇨🇳 繁体中文 (zh-Hant)
    • [x] 🇬🇧 英文 (en)
    • [x] 🇯🇵 日语 (ja)
    • [x] 🇰🇷 韩语 (ko)
    • [x] 🇹🇭 泰语 (th)
    • [x] 🇮🇳 印尼语 (id)
    • [x] 🇻🇳 越南语 (vi)
    • [x] 🇷🇺 俄罗斯 (ru)
    • [x] 🇩🇪 德国 (de)
    • [x] 🇫🇷 法国 (fr)
    • [x] 🇸🇦 阿拉伯 (ar)
    • [x] ✍️ 自定义语言 (custom)
    • [ ] 🤝 更多支持... (欢迎PR)

<a id="要求"></a> 要求

  • iOS 10.0+
  • Xcode 12.5+
  • Swift 5.4+

<a id="安装"></a> 安装

Swift Package Manager

⚠️ 需要 Xcode 13.0 及以上版本来支持资源文件/本地化文件的添加。

dependencies: [
    .package(url: "https://github.com/SilenceLove/HXPhotoPicker.git", .upToNextMajor(from: "5.0.5"))
]

CocoaPods

将下面内容添加到 Podfile,并执行依赖更新。


/// iOS 10.0+ 默认不支持GIF和网络图片
pod 'HXPhotoPicker'

/// 使用`SwiftyGif`加载GIF图片
pod 'HXPhotoPicker/SwiftyGif'

/// 使用`SDWebImage`加载GIF/网络图片
pod 'HXPhotoPicker/SDWebImage'

/// 使用`Kingfisher v6.0.0`加载GIF/网络图片
pod 'HXPhotoPicker/Kingfisher'

/// 相机不包含定位功能
pod `HXPhotoPicker/NoLocation`

/// 只有选择器
pod `HXPhotoPicker/Picker`

/// 只有编辑器
pod `HXPhotoPicker/Editor`

/// 只有相机
pod `HXPhotoPicker/Camera`
/// 不包含定位功能
pod `HXPhotoPicker/Camera/Lite`

v4.0以下的ObjC版本
pod 'HXPhotoPickerObjC'

准备工作

按需在你的 Info.plist 中添加以下键值:

| Key | 模块 | 备注 | | ----- | ---- | ---- | | NSPhotoLibraryUsageDescription | Picker | 允许访问相册 | | NSPhotoLibraryAddUsageDescription | Picker | 允许保存图片至相册 | | PHPhotoLibraryPreventAutomaticLimitedAccessAlert | Picker | 设置为 YES iOS 14+ 以禁用自动弹出添加更多照片的弹框(Picker 已适配 Limited 功能,可由用户主动触发,提升用户体验) | | NSCameraUsageDescription | Camera | 允许使用相机 | | NSMicrophoneUsageDescription | Camera | 允许使用麦克风 |

<a id="示例"></a> 快速上手

import HXPhotoPicker

class ViewController: UIViewController {

    func presentPickerController() {
        // 设置与微信主题一致的配置
        let config = PickerConfiguration.default
        
        // 方法一:async/await
        // 使用`Photo`
        let images: [UIImage] = try await Photo.picker(config)
        let urls: [URL] = try await Photo.picker(config)
        let urlResult: [AssetURLResult] = try await Photo.picker(config)
        let assetResult: [AssetResult] = try await Photo.picker(config)
        // 使用`PhotoPickerController`
        let images: [UIImage] = try await PhotoPickerController.picker(config)
        let urls: [URL] = try await PhotoPickerController.picker(config)
        let urlResult: [AssetURLResult] = try await PhotoPickerController.picker(config)
        let assetResult: [AssetResult] = try await PhotoPickerController.picker(config)
        
        let pickerResult = try await Photo.picker(config)
        let images: [UIImage] = try await pickerResult.objects()
        let urls: [URL] = try await pickerResult.objects()
        let urlResults: [AssetURLResult] = try await pickerResult.objects()
        let assetResults: [AssetResult] = try await pickerResult.objects()
        
        // 方法二:
        let pickerController = PhotoPickerController(picker: config)
        pickerController.pickerDelegate = self
        // 当前被选择的资源对应的 PhotoAsset 对象数组
        pickerController.selectedAssetArray = selectedAssets 
        // 是否选中原图
        pickerController.isOriginal = isOriginal
        present(pickerController, animated: true, completion: nil)
        
        // 方法三:
        Photo.picker(
            config
        ) { result, pickerController in
            // 选择完成的回调
            // result 选择结果
            //  .photoAssets 当前选择的数据
            //  .isOriginal 是否选中了原图
            // photoPickerController 对应的照片选择控制器
        } cancel: { pickerController in
            // 取消的回调
            // photoPickerController 对应的照片选择控制器 
        }
    }
}

extension ViewController: PhotoPickerControllerDelegate {
    
    /// 选择完成之后调用
    /// - Parameters:
    ///   - pickerController: 对应的 PhotoPickerController
    ///   - result: 选择的结果
    ///     result.photoAssets  选择的资源数组
    ///     result.isOriginal   是否选中原图
    func pickerController(
        _ pickerController: PhotoPickerController, 
        didFinishSelection result: PickerResult
    ) {
        // async/await
        let images: [UIImage] = try await result.objects()
        let urls: [URL] = try await result.objects()
        let urlResults: [AssetURLResult] = try await result.objects()
        let assetResults: [AssetResult] = try await result.objects()
        
        result.getImage { (image, photoAsset, index) in
            if let image = image {
                print("success", image)
            }else {
                print("failed")
            }
        } completionHandler: { (images) in
            print(images)
        }
    }
    
    /// 点击取消时调用
    /// - Parameter pickerController: 对应的 PhotoPickerController
    func pickerController(didCancel pickerController: PhotoPickerController) {
        
    }
}

<a id="如何支持GIF/网络图片"></a> 如何支持GIF/网络图片 HXImageViewProtocol

<details> <summary><strong><a href="https://github.com/SilenceLove/HXPhotoPicker/tree/master/Sources/ImageView/GIFImageView.swift">SwiftyGif</a> </strong></summary>
PickerConfiguration.imageViewProtocol = GIFImageView.self

public class GIFImageView: UIImageView, HXImageViewProtocol {
    public func setImageData(_ imageData: Data?) {
        guard let imageData else {
            clear()
            SwiftyGifManager.defaultManager.deleteImageView(self)
            image = nil
            return
        }
        if let image = try? UIImage(gifData: imageData) {
            setGifImage(image)
        }else {
            image = .init(data: imageData)
        }
    }
    
    public func _startAnimating() {
        startAnimatingGif()
    }
    
    public func _stopAnimating() {
        stopAnimatingGif()
    }
}
</details> <details> <summary><strong><a href="https://github.com/SilenceLove/HXPhotoPicker/tree/master/Sources/ImageView/SDImageView.swift">SDWebImage</a></strong></summary>
PickerConfiguration.imageViewProtocol = SDImageView.self

public class SDImageView: SDAnimatedImageView, HXImageViewProtocol {
    public func setImageData(_ imageData: Data?) {
        guard let imageData else { return }
        let image = SDAnimatedImage(data: imageData)
        self.image = image
    }
    
    @discardableResult
    public func setImage(with resource: ImageDownloadResource, placeholder: UIImage?, options: ImageDownloadOptionsInfo?, progressHandler: ((CGFloat) -> Void)?, completionHandler: ((Result<UIImage, ImageDownloadError>) -> Void)?) -> ImageDownloadTask? {
        var sdOptions: SDWebImageOptions = []
        var context: [SDWebImageContextOption: Any] = [:]
        if let options {
            for option in options {
                switch option {
                case .imageProcessor(let size):
                    let imageProcessor = SDImageResizingTransformer(size: size, scaleMode: .aspectFill)
                    context[.imageTransformer] = imageProcessor
                case .onlyLoadFirstFrame:
                    sdOptions.insert(.decodeFirstFrameOnly)
                case .memoryCacheExpirationExpired:
                    sdOptions.insert(.refreshCached)
                case .cacheOriginalImage, .fade, .scaleFactor:
                    break
                }
            }
        }
        sd_setImage(with: resource.downloadURL, placeholderImage: placeholder, options: sdOptions, context: context) { receivedSize, totalSize, _ in
            let progress = CGFloat(receivedSize) / CGFloat(totalSize)
            DispatchQueue.main.async {
                progressHandler?(progress)
            }
        } completed: { image, error, cacheType, sourceURL in
            if let image {
                com

Related Skills

View on GitHub
GitHub Stars3.4k
CategoryCustomer
Updated2d ago
Forks734

Languages

Swift

Security Score

100/100

Audited on Mar 26, 2026

No findings