打造 iMessage 风格图片选择器:ImagePickerSheetController 完全指南

打造 iMessage 风格图片选择器:ImagePickerSheetController 完全指南

【免费下载链接】ImagePickerSheetController ImagePickerSheetController replicates the custom photo action sheet in iMessage. 【免费下载链接】ImagePickerSheetController 项目地址: https://gitcode.com/gh_mirrors/im/ImagePickerSheetController

你是否在开发 iOS 应用时,希望实现像 iMessage 那样优雅的图片选择交互?是否厌倦了系统默认 UIImagePickerController 的单调样式?ImagePickerSheetController 正是为解决这些痛点而生——它完美复刻了 iMessage 中的自定义照片操作面板,提供流畅的动画过渡和直观的多选体验。本文将带你从基础集成到高级定制,全面掌握这个强大组件的使用技巧。

为什么选择 ImagePickerSheetController?

传统图片选择方案存在三大痛点:系统默认组件样式与应用设计脱节、多选交互体验差、权限请求与媒体处理逻辑繁琐。ImagePickerSheetController 通过以下特性彻底解决这些问题:

  • iMessage 风格交互:底部滑出式面板,支持预览图横向滚动与动态放大
  • 类 UIAlertController API:熟悉的接口设计,降低学习成本
  • 完整媒体处理:同时支持图片/视频选择,内置 PHAsset 管理
  • 高度可定制:支持自定义操作按钮、选择限制与回调处理

ImagePickerSheetController 演示

核心概念与架构设计

ImagePickerSheetController 采用分层架构设计,主要包含三个核心组件:

mermaid

核心类解析

  1. ImagePickerSheetController:主控制器,负责媒体类型配置、资产管理与生命周期

    • mediaType:指定选择类型(.image/.video/.imageAndVideo)
    • maximumSelection:设置最大可选数量
    • selectedAssets:获取选中的媒体资源
  2. ImagePickerAction:操作按钮模型,类似 UIAlertAction

    • 主标题/次要标题双状态显示
    • 支持普通/取消样式区分
    • 主操作/次要操作双回调处理
  3. PreviewCollectionView:媒体预览组件

    • 横向滚动布局
    • 选中状态动画
    • 动态高度调整

快速集成指南

环境要求

  • iOS 9.0+
  • Swift 3.0+
  • Photos.framework 权限

安装方式

CocoaPods 集成
pod "ImagePickerSheetController", "~> 0.9.1"
Carthage 集成
github "lbrndnr/ImagePickerSheetController" ~> 0.9.1

权限配置

在 Info.plist 中添加必要权限说明:

<key>NSCameraUsageDescription</key>
<string>需要访问相机拍摄照片/视频</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册选择媒体文件</string>

基础使用教程

标准初始化流程

// 创建控制器实例,指定媒体类型
let controller = ImagePickerSheetController(mediaType: .imageAndVideo)
controller.maximumSelection = 5  // 最多选择5项
controller.delegate = self       // 设置代理

// 添加操作按钮
controller.addAction(ImagePickerAction(
    title: "拍摄照片/视频",
    secondaryTitle: "添加评论",
    handler: { _ in
        // 主操作:打开相机
        self.presentImagePickerController(.camera)
    },
    secondaryHandler: { _, count in
        // 次要操作:处理选中的count张照片
        print("评论 \(count) 张照片")
    }
))

// 展示控制器
present(controller, animated: true, completion: nil)

完整示例代码

// ViewController.swift
import ImagePickerSheetController

class MediaViewController: UIViewController, ImagePickerSheetControllerDelegate {
    
    @IBAction func showPickerTapped(_ sender: UIButton) {
        let presentImagePicker: (UIImagePickerController.SourceType) -> Void = { source in
            let picker = UIImagePickerController()
            picker.sourceType = source
            picker.delegate = self
            self.present(picker, animated: true)
        }
        
        // 创建选择器控制器
        let sheetController = ImagePickerSheetController(mediaType: .imageAndVideo)
        sheetController.maximumSelection = 3
        sheetController.delegate = self
        
        // 添加相机操作
        sheetController.addAction(ImagePickerAction(
            title: "拍摄照片/视频",
            secondaryTitle: "添加评论",
            handler: { _ in
                presentImagePicker(.camera)
            },
            secondaryHandler: { _, count in
                print("评论 \(count) 张照片")
            }
        ))
        
        // 添加相册操作
        sheetController.addAction(ImagePickerAction(
            title: "照片库",
            secondaryTitle: { "发送 \($0) 张照片" },
            handler: { _ in
                presentImagePicker(.photoLibrary)
            },
            secondaryHandler: { _, count in
                print("已选择: \(sheetController.selectedAssets.count) 项")
            }
        ))
        
        // 添加取消操作
        sheetController.addAction(ImagePickerAction(
            title: "取消",
            style: .cancel,
            handler: { _ in
                // 取消逻辑
            }
        ))
        
        // iPad适配:使用弹窗展示
        if UIDevice.current.userInterfaceIdiom == .pad {
            sheetController.modalPresentationStyle = .popover
            sheetController.popoverPresentationController?.sourceView = sender
            sheetController.popoverPresentationController?.sourceRect = sender.bounds
        }
        
        present(sheetController, animated: true)
    }
    
    // MARK: - ImagePickerSheetControllerDelegate
    func controllerDidEnlargePreview(_ controller: ImagePickerSheetController) {
        print("预览区域已放大")
    }
    
    func controller(_ controller: ImagePickerSheetController, didSelectAsset asset: PHAsset) {
        print("已选择资产: \(asset.localIdentifier)")
    }
}

高级定制技巧

1. 自定义预览布局

通过修改 PreviewCollectionView 的布局属性实现个性化展示:

// 获取预览集合视图
let previewLayout = controller.previewCollectionView.collectionViewLayout as! PreviewCollectionViewLayout
previewLayout.sectionInset = UIEdgeInsets(top: 8, left: 12, bottom: 8, right: 12)
previewLayout.minimumInteritemSpacing = 10

2. 多语言支持配置

使用 stringsdict 实现多语言复数处理:

<!-- Localizable.stringsdict -->
<dict>
    <key>ImagePickerSheet.button1.Send %lu Photo</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%#@photos@</string>
        <key>photos</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>lu</string>
            <key>one</key>
            <string>发送 %lu 张照片</string>
            <key>other</key>
            <string>发送 %lu 张照片</string>
        </dict>
    </dict>
</dict>

3. 媒体资产处理

通过 PHAsset 获取完整资源:

// 处理选中的资产
func processSelectedAssets(_ assets: [PHAsset]) {
    let imageManager = PHCachingImageManager()
    let options = PHImageRequestOptions()
    options.deliveryMode = .highQualityFormat
    
    for asset in assets {
        imageManager.requestImage(
            for: asset,
            targetSize: CGSize(width: 800, height: 800),
            contentMode: .aspectFill,
            options: options
        ) { image, info in
            // 处理获取到的图片
            if let image = image {
                self.processedImages.append(image)
            }
        }
    }
}

常见问题解决方案

1. 模拟器兼容性问题

问题:模拟器中无法使用相机功能
解决:实现自动回退逻辑

func presentImagePickerController(_ source: UIImagePickerController.SourceType) {
    let picker = UIImagePickerController()
    var sourceType = source
    
    // 检查设备是否支持指定源类型
    if !UIImagePickerController.isSourceTypeAvailable(sourceType) {
        sourceType = .photoLibrary
        print("模拟器不支持相机,自动切换到相册")
    }
    
    picker.sourceType = sourceType
    present(picker, animated: true)
}

2. 性能优化策略

  • 资产预加载:限制最大加载数量(默认50)
  • 图片缓存:使用 PHCachingImageManager 缓存缩略图
  • 按需加载:实现滑动时暂停加载,停止时恢复
// 优化资产加载
controller.prepareAssets() {
    // 预加载完成回调
    DispatchQueue.main.async {
        controller.previewCollectionView.reloadData()
    }
}

3. 适配深色模式

// 自定义预览选中样式
override func viewDidLoad() {
    super.viewDidLoad()
    
    if #available(iOS 13.0, *) {
        previewCollectionView.tintColor = .systemBlue
        previewCollectionView.backgroundColor = .systemBackground
    }
}

最佳实践与注意事项

1. 内存管理

  • 及时释放 PHImageManager 请求
  • 避免强引用循环:在闭包中使用 [weak self]
controller.addAction(ImagePickerAction(
    title: "照片库",
    handler: { [weak self] _ in
        guard let self = self else { return }
        self.presentImagePicker(.photoLibrary)
    }
))

2. 用户体验优化

  • 提供清晰的权限申请说明
  • 加载状态提示:使用 UIActivityIndicatorView
  • 空状态处理:当相册为空时显示引导提示

3. 测试策略

  • 测试不同权限状态下的表现
  • 验证各种媒体类型(图片/视频/连拍照片)
  • 测试边界情况:最大选择数、横屏/竖屏切换

总结与展望

ImagePickerSheetController 为 iOS 开发者提供了一个高度可定制的媒体选择解决方案,其核心优势在于:

  1. 原生体验:完美复刻 iMessage 交互模式
  2. 灵活扩展:通过代理和样式属性支持深度定制
  3. 完整功能:涵盖拍摄/选择/预览/处理全流程

未来版本可能的改进方向:

  • SwiftUI 支持
  • iOS 14+ 照片选择 API 适配
  • 视频缩略图与时长显示优化

通过本文的指南,你应该已经掌握了从基础集成到高级定制的全部要点。现在就将这个强大的组件集成到你的项目中,为用户提供流畅直观的媒体选择体验吧!

【免费下载链接】ImagePickerSheetController ImagePickerSheetController replicates the custom photo action sheet in iMessage. 【免费下载链接】ImagePickerSheetController 项目地址: https://gitcode.com/gh_mirrors/im/ImagePickerSheetController

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值