2016-05-05 23:12:37 xxh0307 阅读数 10246

2017年5月11更新

添加了拍照,也就是现在是拍照、相册两个选项了。为了自己在项目中更方便的调用,也简单的封装了一个方法。

HsuPhotosManager.swift文件
/// 添加图片
///
/// - Parameters:
///   - phtotsCount: 几张
///   - showCamera: 是否相机
///   - showAlbum: 是否相册
///   - _completeHandler: 回调
func takePhotos(_ photosCount: Int, _ showCamera: Bool, _ showAlbum: Bool, _ completeHandler: @escaping ([Data?]) -> Void) 

2017年4月6日更新

前面的前面

最尴尬的莫过于自己参考自己写的东西并且还是过时不能用的。今天使用 Swift3.1 重新封装了选择系统相册的功能,参考了苹果 simple code

效果:
效果

项目地址

项目介绍:

待更新 。。。

前言

毕竟刚开始接触Swift语言,很多写的地方可能多有不规范,并且也许不少知识点都是一知半解的状态,但是现在的精力和能力如果点点都要理得通,毕竟自己从中得到一些体会,也希望能帮助一些刚刚入门的小伙伴。

首先,第一次写这个的时候,源于一次偶尔看到 苹果官方Photos的SimpleCode ,我用OC写的demo其实就是抽取了这个code一部分的内容,效果如下:

当然今天这个并不是重点,现在我用Swift重写了一遍,一共也就200多行代码吧。主要涉及PHAsset、CollectionView的代码布局和故事版布局。

全部代码逐步实现选取图片

首先说一下大致规划,所有图片页面,即AllPhotosViewController 我用的纯代码,为了方便扔到项目中同事拿来直接用,选择图片后带回来展示我用故事版Storyboard画的collectionView。

  1. 创建一个空的项目工程,并在首页放置一个按钮,用于跳转到下一页,如下图和代码示例:

    首页放置一个按钮

    //  按钮事件,点击选择系统相册
    @IBAction func clickedAction(sender: UIButton) {
        //  跳转页面
        let photosVC = BBAllPhotosViewController()
        presentViewController(photosVC, animated: true, completion: nil)
    }
  2. 给第二个页面添加基本的控件

    给第二个页面添加控件,headerView,包括标题和右侧返回按钮。bottomView,包括完成按钮和已选择图片数量,默认初始是不显示的,当选择图片的时候会显示。这里不会对语法有过多的讲解,毕竟细节说的话太多,我在代码中也添加了一些注释。另外,这么多代码其实每一句有技术含量的代码,都是一些无脑代码创建控件,此时充分体现storyboard是多么的节约代码。

    import UIKit
    
    class BBAllPhotosViewController: UIViewController {
    
     //  屏幕宽高
        private var KSCREEN_HEIGHT =  UIScreen.mainScreen().bounds.size.height
        private var KSCREEN_WIDTH =  UIScreen.mainScreen().bounds.size.width
    
        //  头视图,显示标题和取消按钮
        private let headerView = UIView()
        //  默认头视图高度
        private var defaultHeight: CGFloat = 50
    
        //  底部视图,UIButton,点击完成
        private let completedButton = UIButton()
        //  已选择图片数量
        private let countLable = UILabel()
    
        override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .whiteColor()
    
        //  添加顶部、底部视图
        addHeadViewAndBottomView()
        }
    
        //  MARK:- 添加headerView-标题、取消 , 添加底部视图,包括完成按钮和选择数量
        private func addHeadViewAndBottomView() {
        //  headerView
        headerView.frame = CGRectMake(0, 0, KSCREEN_WIDTH, defaultHeight)
        headerView.backgroundColor = UIColor.init(colorLiteralRed: 0, green: 0, blue: 0, alpha: 0.6)
        view.addSubview(headerView)
    
        //  添加返回按钮
        let backButton = UIButton()
        backButton.frame = CGRectMake(0, 0, 60, 30)
        backButton.setTitle("取消", forState: .Normal)
        backButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        backButton.center = CGPointMake(KSCREEN_WIDTH - 40, defaultHeight / 1.5)
        backButton.titleLabel?.font = UIFont.systemFontOfSize(17)
        //  注意这里给按钮添加点击方法的写法
        backButton.addTarget(self, action:#selector(BBAllPhotosViewController.dismissAction),
                             forControlEvents: .TouchUpInside)
        headerView.addSubview(backButton)
    
        //  标题
        let titleLable = UILabel(frame: CGRectMake(0, 0, KSCREEN_WIDTH / 2, defaultHeight))
        titleLable.text = "全部图片"
        titleLable.textColor = UIColor.whiteColor()
        titleLable.font = UIFont.systemFontOfSize(19)
        titleLable.textAlignment = .Center
        titleLable.center = CGPointMake(KSCREEN_WIDTH / 2, defaultHeight / 1.5)
        headerView.addSubview(titleLable)
    
        //  底部View,点击选择完成
        completedButton.frame = CGRectMake(0, KSCREEN_HEIGHT, KSCREEN_WIDTH, 44)
        completedButton.backgroundColor = UIColor.init(white: 0.8, alpha: 1)
        view .addSubview(completedButton)
    
        //  完成按钮
        let overLabel = UILabel(frame: CGRectMake(KSCREEN_WIDTH / 2 + 10, 0, 40, 44))
        overLabel.text = "完成"
        overLabel.textColor = UIColor.greenColor()
        overLabel.font = UIFont.systemFontOfSize(18)
        completedButton .addSubview(overLabel)
    
        //  已选择图片数量
        countLable.frame = CGRectMake(KSCREEN_WIDTH / 2 - 25, 10, 24, 24)
        countLable.backgroundColor = UIColor.greenColor()
        countLable.textColor = UIColor.whiteColor()
        countLable.layer.masksToBounds = true
        countLable.layer.cornerRadius = countLable.bounds.size.height / 2
        countLable.textAlignment = .Center
        countLable.font = UIFont.systemFontOfSize(16)
        completedButton .addSubview(countLable)
        }
    
        //  取消选择,返回上一页
        func dismissAction() {
        self .dismissViewControllerAnimated(true, completion: nil)
            }
        }
    
  3. 获取系统全部图片
    这里就要说一点东西了。首先iOS8之后,苹果开放了一个新的包Photos,更方便我们获取系统的所有图片,但是取到图片的时候,这些图片本身并不是image类型的,而是PHAsset单元。PHAsset类型的数据单元内包括拍照时间、经纬度、修改时间等具体信息,这个就不扩展了,毕竟挺多的一部分。其实我更喜欢把说明放到注释里,这样的话看代码的时候就可以清晰的知道代码具体什么作用。至少我看别人技术博客的时候就希望可以有个详细的注释。也许不知道什么是PHAsset,但是并不会影响读代码。代码中会有大量的注释。注意对比前文代码查看修改内容。

    由上往下,先引入Photos包,并且引入需要实现的协议。

     import UIKit
     import Photos
             class BBAllPhotosViewController: UIViewController , PHPhotoLibraryChangeObserver{

    在 viewDidLoad方法中,添加获取所有图片的方法。

         override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .whiteColor()
    
            //  添加顶部、底部视图
            addHeadViewAndBottomView()
    
            //  获取全部图片
            getAllPhotos()
        }

    最后,实现获取图片的方法以及第一次获取图片时的观察者方法。我这里做了最简单的处理,就是第一次进入的时候再次获取图片。其实这个方法只会执行一次,再次运行程序就不会执行这个方法了,所以我认为这么写也没什么大的问题。

    //  MARK:- 获取全部图片
        private func getAllPhotos() {
        //  注意点!!-这里必须注册通知,不然第一次运行程序时获取不到图片,以后运行会正常显示。体验方式:每次运行项目时修改一下 Bundle Identifier,就可以看到效果。
        PHPhotoLibrary.sharedPhotoLibrary().registerChangeObserver(self)
        //  获取所有系统图片信息集合体
        let allOptions = PHFetchOptions()
        //  对内部元素排序,按照时间由远到近排序
        allOptions.sortDescriptors = [NSSortDescriptor.init(key: "creationDate", ascending: true)]
        //  将元素集合拆解开,此时 allResults 内部是一个个的PHAsset单元
        let allResults = PHAsset.fetchAssetsWithOptions(allOptions)
        print(allResults.count)
        }
        //  PHPhotoLibraryChangeObserver  第一次获取相册信息,这个方法只会进入一次
        func photoLibraryDidChange(changeInstance: PHChange) {
        getAllPhotos()
        }

    因为我们获取到信息后执行了 print 打印方法,所以程序到现在运行时控制台会有数量输出的,如果没有,那就是前面某个小步骤出问题了。

  4. 设置容器 CollectionView

    这里我用了纯代码布局,主要用了collectionView的两个dataSource协议方法,代码里有具体的注释。先测试能不能正常显示。同时,自定义一个cell用来展示数据。其实大多数使用CollectionView的时候都要自定义cell,毕竟原生的展示太简单了些。目前所有的代码都是在 BBAllPhotosViewController.swift 文件中操作的。

    • 添加collectionView协议 UICollectionViewDelegateFlowLayout, UICollectionViewDataSource,同时添加必要的全局属性,注意与上面代码的对比。
    //  载体
    private var myCollectionView: UICollectionView!
    //  collectionView 布局
    private let flowLayout = UICollectionViewFlowLayout()
    //  collectionviewcell 复用标识
    private let cellIdentifier = "myCell"
    //  数据源
    private var photosArray = PHFetchResult()
    //  已选图片数组,数据类型是 PHAsset
    private var seletedPhotosArray = [PHAsset]()
    
    
    //  MARK:- lifeCycle
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .whiteColor()
    
        //  添加顶部、底部视图
        addHeadViewAndBottomView()
    
        //  添加collectionView
        createCollectionView()
    
        //  获取全部图片
        getAllPhotos()
    }
    
    • collectionView相关的代码,主要就是展示方面的。还有目前需要的两个协议方法。
    //  MARK:- 创建 CollectionView 并实现协议方法 delegate / dataSource
    private func createCollectionView() {
        // 竖屏时每行显示4张图片
        let shape: CGFloat = 5
        let cellWidth: CGFloat = (KSCREEN_WIDTH - 5 * shape) / 4
        flowLayout.sectionInset = UIEdgeInsetsMake(0, shape, 0, shape)
        flowLayout.itemSize = CGSizeMake(cellWidth, cellWidth)
        flowLayout.minimumLineSpacing = shape
        flowLayout.minimumInteritemSpacing = shape
        //  collectionView
        myCollectionView = UICollectionView(frame: CGRectMake(0, defaultHeight, KSCREEN_WIDTH, KSCREEN_HEIGHT - defaultHeight), collectionViewLayout: flowLayout)
        myCollectionView.backgroundColor = .whiteColor()
        //  添加协议方法
        myCollectionView.delegate = self
        myCollectionView.dataSource = self
        //  设置 cell
        myCollectionView.registerClass(MyCollectionViewCell.self, forCellWithReuseIdentifier: cellIdentifier)
        view.addSubview(myCollectionView)
    }
    
    //  collectionView delegate
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell
        return cell
    }
    
    • 自定义cell,cell有两个控件,一个是图片用于展示,还有一个展示是否被选择的控件。有一个choose属性,判断cell是否被选择,并添加属性监测,保证和是否被选择标识同步。在 BBAllPhotosViewController.swift 文件添加这个类。
    //  MARK:- CollectionViewCell
    class MyCollectionViewCell: UICollectionViewCell {
    
    let selectButton = UIButton()
    let imageView = UIImageView()
    //  cell 是否被选择
    var isChoose = false {
        didSet {
            selectButton.selected = isChoose
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    
    //  展示图片
        imageView.frame = contentView.bounds
        imageView.contentMode = .ScaleToFill
        imageView.clipsToBounds = true
        contentView.addSubview(imageView)
        imageView.backgroundColor = .cyanColor()
    
    //  展示图片选择图标
        selectButton.frame = CGRectMake(contentView.bounds.size.width * 3 / 4 - 2, 2, contentView.bounds.size.width / 4 , contentView.bounds.size.width / 4)
        selectButton.setBackgroundImage(UIImage.init(named: "iw_unselected"), forState: .Normal)
        selectButton.setBackgroundImage(UIImage.init(named: "iw_selected"), forState: .Selected)
        imageView.addSubview(selectButton)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }  
    }

    此时应该是能看到一丢丢的效果了,下一步替换数据后就好看多了。

  5. 替换数据,展示选择效果。把获取到的所有图片数据赋值给数据源数组,并刷新collectionView,同时添加选择效果。看代码看代码,写文字太累。

    //  collectionView dateSource
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return photosArray.count
    }
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell
    //  展示图片
    PHCachingImageManager.defaultManager().requestImageForAsset(photosArray[indexPath.row] as! PHAsset, targetSize: CGSizeZero, contentMode: .AspectFit, options: nil) { (result: UIImage?, dictionry: Dictionary?) in
            cell.imageView.image = result ?? UIImage.init(named: "iw_none")
        }
        return cell
    }
    
    //  collectionView delegate
       //  collectionView delegate
    func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        let currentCell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCollectionViewCell
        currentCell.isChoose = !currentCell.isChoose
        seletedPhotosArray.append(photosArray[indexPath.row] as! PHAsset)
        completedButtonShow()
    }

    这里我要说一个我自己也没搞明白的东西,就是官方API接口获取图片的方法

    PHCachingImageManager.defaultManager().requestImageForAsset(<#T##asset: PHAsset##PHAsset#>, targetSize: <#T##CGSize#>, contentMode: <#T##PHImageContentMode#>, options: <#T##PHImageRequestOptions?#>, resultHandler: <#T##(UIImage?, [NSObject : AnyObject]?) -> Void#>)

    这个方法中targetSize是我至今没有搞明白的地方,当初OC写的时候不明白,现在还不是太明白。我在Stack Overflow找到一个答案说是如果图片真实大小小于自己限定的,就会取真实的,如果大于targetSize,则以targetSize为准。但是我在测试的时候出现了问题。这个方法内部会执行两次,第一次是返回一个(60,40)的缩略图,同时如果targetSize设置为CGSizeZero就会只执行一次,并且即使手机有几千张图片,内存消耗也稳定在13M左右。我尝试设置targetSize为CGSizeMake(800, 600),发现很多返回照片的大小远远高于这个值,200多张照片就把程序搞崩了~~以后自己搞明白的话再来补充吧。建议自己写代码的时候在这里多试几次,同事打印输出返回图片的详细信息。

    选择图片后动态展示选择数量:

    //  MARK:- 展示和点击完成按钮
    func completedButtonShow() {
        var originY: CGFloat
    
      if seletedPhotosArray.count > 0 {
            originY = KSCREEN_HEIGHT - 44
            flowLayout.sectionInset.bottom = 44
        } else {
            originY = KSCREEN_HEIGHT
            flowLayout.sectionInset.bottom = 0
        }
    
        UIView.animateWithDuration(0.2) {
            self.completedButton.frame.origin.y = originY
            self.countLable.text = String(self.seletedPhotosArray.count)
    
            //  仿射变换
            UIView.animateWithDuration(0.2, animations: {
                self.countLable.transform = CGAffineTransformMakeScale(0.35, 0.35)
                self.countLable.transform = CGAffineTransformScale(self.countLable.transform, 3, 3)
            })
        }
    }

    看看现在的效果吧,同时也会发现新的问题。

    问题就是由于cell自身的复用,导致选择的标识重复出现。个人感觉处理这个问题是我在这个练习中比较大的一个收获。说一下思路,创建一个数组,数量和数据源数组的count保持一致。里面都是一些0、1标识,其实0代表未选择,1代表选择。根据一一对应的关系,保证每次点击的cell都是唯一的。整个代码中共有2个地方使用这个数组,分别是return cell 方法中和didSelectItemAtIndexPath方法。具体的代码看下面的全部代码展示部分吧。

    //  MARK: - 获取全部图片
    private func getAllPhotos() {
        //  注册通知,保证第一次进入后显示照片
        PHPhotoLibrary.sharedPhotoLibrary().registerChangeObserver(self)
    
        let allOptions = PHFetchOptions()
        allOptions.sortDescriptors = [NSSortDescriptor.init(key: "creationDate", ascending: true)]
        let allPhotosResult = PHAsset.fetchAssetsWithOptions(allOptions)
        photosResult = allPhotosResult
    
        //  每个图片设置一个初始标识
        for _ in 0 ..< allPhotosResult.count {
            divideArray.append(0)
        }
    }
  6. 从前一个页面传入选择图片的数量,数量大于9时,选择数为9,数量小于1时,选择数为1。

  7. 添加横竖屏支持。其实就是屏幕旋转时会调用方法 willAnimateRotationToInterfaceOrientation ,这个在代码中有详细的介绍。

  8. 定义一个闭包,将选取的图片带回到上一个页面。更多关于闭包的内容,参考 闭包常用知识分析

  9. 展示带回的图片。其实就是粗略的用故事版拖了一个collectionView。

  10. 补充一点,刚发现,我提交的示例代码有个小细节没有处理。正常情况,选择图片时,应该就像我们微信选择图片一样,进去就是显示最下面的图片,然后向上滑动去选择。其实实现这个很简单,collectionView 提供了系统方法。在 viewWillAppear 方法中添加如下代码即可实现:

     //  页面出现时
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(true)
    
        let indexPath = NSIndexPath(forItem: photosArray.count - 1, inSection: 0)
        myCollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
    }

最终效果:

OC、Swift的 demo 都在这里

OVER
2014-12-23 14:07:59 lcl130 阅读数 1534

UIImagePickerController类管理系统的或者自定义的UI界面来获取设备上的图片和影像,拍照或者录像. ImagePickerController管理这个界面并把获得的结果传递给delegate.

UIImagePickerController根据不同的来源类型(sourceType)来展示不同的界面和实现不同的功能.

UIImagePickerControllerSourceTypeCamera: 拍照或者摄像

UIImagePickerControllerSourceTypePhotoLibrary: 选择图像

UIImagePickerControllerSourceTypeSavedPhotosAlbum: 选择录像

建立UIImagePickerController的步骤:

<span style="font-family:Times New Roman;">//必须遵循UINavigationControllerDelegate和UIImagePickerControllerDelegate哦
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    var imagePickerController:UIImagePickerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //判断是否获得相机
        if ((UIImagePickerController.availableMediaTypesForSourceType(UIImagePickerControllerSourceType.Camera)) != nil) {
            //初始化
            imagePickerController = UIImagePickerController()
            //设置代理
            imagePickerController.delegate = self;
            //设置类型
            imagePickerController.sourceType = .Camera
            //设置是否能够编辑
            imagePickerController.allowsEditing = true
            //展示UIImagePickerController
            self.presentViewController(imagePickerController, animated: true, completion: {})
        }
    }

    //delegate方法
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
        let dic = info as NSDictionary
        //原始图片
        let image = dic.objectForKey("UIImagePickerControllerOriginalImage") as UIImage
        //编辑过后的图片
        let editedImage = dic.objectForKey("UIImagePickerControllerEditedImage") as UIImage
        //MediaType
        let mediaType = dic.objectForKey("UIImagePickerControllerMediaType") as String
    }
    
    func imagePickerControllerDidCancel(picker: UIImagePickerController) {
        
    }
}</span>
UIImagePickerViewController的界面可以自定义

<span style="font-family:Times New Roman;font-size:12px;"></span><pre name="code" class="objc"><span style="font-family:Times New Roman;">            //自定义UIImagePickerController的UI界面
            imagePickerController.showsCameraControls = false
            //1.覆盖涂层
            let view = UIView() //自定义的View
            view.frame = imagePickerController.cameraOverlayView!.frame
            imagePickerController.cameraOverlayView = view;
            //2.设置相机内容视图的大小
            imagePickerController.cameraViewTransform = CGAffineTransformScale(imagePickerController.view.transform, 0.9, 0.9)</span>



照相的实现

<span style="font-family:Times New Roman;"></span><pre name="code" class="objc"><span style="font-family:Times New Roman;">            //判断相机设备是否可用
            let frontCameraAviable = UIImagePickerController.isCameraDeviceAvailable(.Front)
            //相机设备支持的模式,返回NSNumber数组,[Photo,Vedio]
            let cameraModel = UIImagePickerController.availableCaptureModesForCameraDevice(.Front)
            //相机设备支持闪光灯与否
            let canFlashOrNot = UIImagePickerController.isFlashAvailableForCameraDevice(.Front)
            
            //设置相机设备,前置或者后置摄像头
            imagePickerController.cameraDevice = .Front
            //设置相机的模式
            imagePickerController.cameraCaptureMode = .Photo
            //设置闪光灯模式
            imagePickerController.cameraFlashMode = .On</span>

//拍照
imagePickerController.takePicture()

录像相关
<span style="font-family:Times New Roman;">            //录像的质量
            imagePickerController.videoQuality = .TypeHigh
            //录像的是长,默认10分钟
            imagePickerController.videoMaximumDuration = 20
            //开始录像
            imagePickerController.startVideoCapture()
            //停止录像
            imagePickerController.stopVideoCapture()</span>
五个常量

<span style="font-family:Times New Roman;">enum UIImagePickerControllerSourceType : Int {//数据源
    
    case PhotoLibrary
    case Camera
    case SavedPhotosAlbum
}

enum UIImagePickerControllerQualityType : Int {//视频的画质
    
    case TypeHigh // highest quality
    case TypeMedium // medium quality, suitable for transmission via Wi-Fi 
    case TypeLow // lowest quality, suitable for tranmission via cellular network
    
    case Type640x480 // VGA quality
    
    case TypeIFrame1280x720
    case TypeIFrame960x540
}

enum UIImagePickerControllerCameraCaptureMode : Int {//相机模式
    
    case Photo
    case Video
}

enum UIImagePickerControllerCameraDevice : Int {//相机类型
    
    case Rear
    case Front
}

enum UIImagePickerControllerCameraFlashMode : Int {//闪光灯类型
    
    case Off
    case Auto
    case On
}
</span>


2017-09-16 17:59:50 cyldone 阅读数 934

在实际的项目中,我们经常会用到对相册进行操作的功能,在oc里,这类的框架挺多,也挺好,但是swift里实现这些功能的框架挺少,今天我们来介绍这么一个AlbumCore,完全用swift来实现。

本项目来自已上线应用,源项目经过严格测试,时间有限,demo暂时只抽取了部分内容,核心库架构清晰,原则上可支持更多扩展。

已实现

系统相册浏览,多选
获取图片,视频,获取大小,文件名,URL
相册变更通知,刷新界面

可用,待完善

iCloud相册中内容获取,有一些小问题,后续补上
使用方式

请直接下载demo运行,say is hard,code is easy!

支持pods导入

pod ‘AlbumCore’, ‘~>0.0.4’
具体细节请看代码:

https://github.com/eocleo/AlbumCore/tree/master/AlbumCore

欢迎大家提出建议和star。

2017-08-13 21:41:14 callzjy 阅读数 2709

the best photo picker plugin in swift(iOS8+)



Demo Screenshot


照片选择界面(.weibo)更多效果在下面哦:


参数调节界面


自定义拍照界面


Recently Updated
0.0.5 添加AlertSheet类和useCustomActionSheet配置属性
0.0.4 新增11个属性,向下兼容iOS8,其中最主要的新增功能是2个,1是允许用户选择使用iOS8iOS10拍照功能,推荐仍使用iOS8,默认使用iOS10;2是拍照时是否同时把拍照结果保存到系统相册中去,默认不保存
0.0.3 丰富的参数,DIY你满意的一款photo picker

Features
支持链式编程配置,程序员的最爱
支持Cocoapods
支持2种遮罩模式(直接在选择的照片cell上显示遮罩、选择到最大照片数量后其余照片cell显示遮罩)
支持选择完成后,长按控件的照片cell进行位置调整(iOS 9及以上有效)
支持2种删除模式(选择完成后直接点每个照片cell上的删除按钮删除、选择完成后预览单个照片大图时点工具栏上的删除按钮删除)
支持选择指示器选择时的顺序数字显示(每个照片cell的状态有5种状态:未选择、选中状态、数字选中状态、删除状态、按住删除按钮时的高亮状态)
支持2种选择模式(直接选择、预览选择)
预置weibowechat 2种成组配置模式,省去多个参数配置,简化为一句代码配置
支持8种选择样式(类型)单勾、圈、方块、带、斜带、三角、心、星
支持4种选择位置(左上、左下、右上、右下)
支持tinColor统一设置风格
支持选择指示器大小调节
自由选择iOS8iOS10拍照功能
轻量级、使用超灵活、功能超强大
用例丰富,快速上手

Usage
总体分为2种使用方式,有界面的话,用TGPhotoPicker实例化(即多选照片选择完成后把数据呈现在控件上),不需要界面的话用TGPhotoPickerManager.shared.takePhotoModels单例方法获取多选照片数据(这个又分两种,用模型或不用模型(直接用分开的数组))

提示:
1、请先在info.plist中添加以下两个key,以请求相机相册的访问权限(iOS10
NSCameraUsageDescriptionPrivacy - Camera Usage Description
NSPhotoLibraryUsageDescriptionPrivacy - Photo Library Usage Description
2、作者的Xcode8.3.38E3004b)若你的版本过低,可能会在TGPhotoPickerConfig.swift文件的case .smartAlbumScreenshots:处出现错误提示:Enum case 'smartAlbumScreenshots' not found in type 'PHAssetCollectionSubtype'  报错原因是这是iOS10.2/10.3新增两个值,   解决办法:1、请升级你的Xcode 2、注释相关代码

使用默认(有界面)
lazy var picker: TGPhotoPicker = TGPhotoPicker(self, frame: CGRect(x: 0, y: 50, width: UIScreen.main.bounds.width, height: 200))

override func viewDidLoad() {
        super.viewDidLoad()
        //放到界面中去
        self.view.addSubview(picker)
}

带配置(有界面)
    lazy var picker: TGPhotoPicker = TGPhotoPicker(self, frame: CGRect(x: 0, y: 50, width: UIScreen.main.bounds.width, height: 200)) { (config) in
        config.type = .weibo
        //更多配置在这里添加
    }
带配置(链式)

    lazy var picker: TGPhotoPicker = TGPhotoPicker(self, frame: CGRect(x: 0, y: 50, width: UIScreen.main.bounds.width, height: 200)) { (config) in
        config.tg_type(.wechat)
              .tg_checkboxLineW(1)
    }

带配置(单例配置对象)

    lazy var picker: TGPhotoPicker = TGPhotoPicker(self, frame: CGRect(x: 0, y: 50, width: UIScreen.main.bounds.width, height: 200)) { _ in
        TGPhotoPickerConfig.shared.tg_type(.wechat)
            .tg_checkboxLineW(1)
            .tg_toolBarH(50)
            .tg_useChineseAlbumName(true)
    }

其他使用方式(无界面) 模型数组

TGPhotoPickerManager.shared.takePhotoModels(true, true) { (array) in
            //示例代码
            self.picker.tgphotos.removeAll()
            self.picker.tgphotos.append(contentsOf: array)
            DispatchQueue.main.async {
                self.picker.reloadData()
            }
        }

其他使用方式(无界面) 4个分开独立的数组(即模型里成员分出来的)

TGPhotoPickerManager.shared.takePhotos(true, true, { (config) in
            //链式配置
            config.tg_type(TGPhotoPickerType.weibo)
                .tg_confirmTitle("我知道了")
                .tg_maxImageCount(12)
        }) { (asset, smallImg, bigImg, data) in
            //示例代码
            self.picker.tgphotos.removeAll()
            for i in 0..<smallImg.count {
                let model = TGPhotoM()
                model.asset = asset[i]
                model.smallImage = smallImg[i]
                model.bigImage = bigImg[i]
                model.imageData = data[i]
                self.picker.tgphotos.append(model)
            }
            DispatchQueue.main.async {
                self.picker.reloadData()
            }
        }

使用控件中的数据

func upLoadData(){
        var dataArray = [Data]()
        for model in picker.tgphotos {
            dataArray.append(model.imageData!)
        }
        //上传Data数组
    }


可以配置的属性(以下为部分可以配置的参数,完整配置参数见TGPhotoPickerConfig.swift(其中官方Demo中列出了主要的26个参数的使用效果))
/** Alert样式*/
    var useCustomActionSheet: Bool = true
    
    /** 拍照后是否保存照片到相册*/
    var saveImageToPhotoAlbum: Bool = false
    
    /** 使用iOS8相机: false 根据iOS版本判断使用iOS10或iOS8相机; true 指定使用iOS8相机*/
    var useiOS8Camera: Bool = false
    
    /** 与useCustomSmartCollectionsMask结合使用,当useCustomSmartCollectionsMask为true时过滤需要显示smartAlbum的Album类型*/
    var customSmartCollections 
    
    /** 使用自定义的PHAssetCollectionSubtype集合来过滤显示自己想要的相册夹,如想显示慢动作和自拍,那么上面的useCustomSmartCollectionsMask数组中设置为(或添加)[PHAssetCollectionSubtype.smartAlbumSlomoVideos,PHAssetCollectionSubtype.smartAlbumSelfPortraits]*/
    var useCustomSmartCollectionsMask: Bool = true
    
    /** 是否使用中文名称显示smartAlbum的Album名*/
    var useChineseAlbumName: Bool = false
    
    /** 空内容的相册夹是否显示 */
    var isShowEmptyAlbum: Bool = false
    
    /** 升序排列照片*/
    var ascending: Bool = false
    
    /** 预置的成组配置, 微博 微信*/
    var type: TGPhotoPickerType = .normal
    
    /** 在选择类型为方 带时用到的Corner*/
    var checkboxCorner: CGFloat = 0
    
    /** 选择框显示的位置*/
    var checkboxPosition: TGCheckboxPosition = .topRight
    
    /** 移除按钮显示的位置*/
    var removePosition: TGCheckboxPosition = .topRight
    
    /** 移除类型,同选择类型*/
    var removeType: TGCheckboxType = .diagonalBelt
    
    /** 是否显示选择顺序*/
    var isShowNumber: Bool = true
    
    /** 纯数字模式下显示选择顺序时的数字阴影宽,不需要阴影设置为0*/
    var shadowW:CGFloat = 1.0
    
    /** 纯数字模式下显示选择顺序时的数字阴影高,不需要阴影设置为0*/
    var shadowH:CGFloat = 1.0
    
    /** 选择框类型(样式) 8种 */
    var checkboxType: TGCheckboxType = .diagonalBelt
    
    /** 显示在工具栏上的选择框的大小*/
    var checkboxBarWH: CGFloat = 30
    
    /** 显示在照片Cell上的选择框的大小*/
    var checkboxCellWH: CGFloat = 20
    
    /** 选择框起始透明度*/
    var checkboxBeginngAlpha: CGFloat = 1
    
    /** 选择框的结束透明度, 两者用于选择框渐变效果*/
    var checkboxEndingAlpha: CGFloat = 1
    
    /** 选择框的画线宽度, 工具栏上返回、删除按钮的画线宽度*/
    var checkboxLineW: CGFloat = 1.5
    
    /** 选择框的Padding*/
    var checkboxPadding: CGFloat = 1
    
    /** 选择时是否动画效果*/
    var checkboxAnimate: Bool = true
    
    /** 选择时或选择到最大照片数量时,当前或其他Cell的遮罩的透明度*/
    var maskAlpha: CGFloat = 0.6
    
    /** 使用选择遮罩: false,当选择照片数量达到最大值时,其余照片显示遮罩; true,其余照片不显示遮罩,而是已经选择的照片显示遮罩 */
    var useSelectMask: Bool = false
    
    /** 工具条的高度*/
    var toolBarH: CGFloat = 44.0
    
    /** 相册类型列表Cell的高度*/
    var albumCellH: CGFloat = 60.0
    
    /** 照片Cell的高宽,即选择时的呈现的宽高*/
    var selectWH: CGFloat = 80
    
    /** 控件本身的Cell的宽高,即选择后的呈现的宽高*/
    var mainCellWH: CGFloat = 80
    
    /** 自动宽高,用于控件本身Cell的宽高自动计算*/
    var autoSelectWH: Bool = false
    
    /** true,在选择照片界面,点击照片(非checkbox区域)时,不跳转到大图预览界面,而是直接选择或取消选择当前照片; false, 点击照片checkbox区域选择或取消选择当前照片,点击非checkbox区域跳转到大图预览界面*/
    var immediateTapSelect: Bool = false
    
    /** 控件或Cell之间布局时的padding*/
    var padding: CGFloat = 1
    
    /** 左右没有空白,即选择时呈现的UICollectionView没有contentInset中的左右Inset*/
    var leftAndRigthNoPadding: Bool = true
    
    /** 选择时呈现的UICollectionView的每行列数*/
    var colCount: CGFloat = 4
    
    /** 选择后控件本身呈现的UICollectionView的每行列数*/
    var mainColCount: CGFloat = 4
    
    /** 完成按钮标题*/
    var doneTitle = "完成"
    
    /** 完成按钮的宽*/
    var doneButtonW: CGFloat = 70
    
    /** 完成按钮的高*/
    var doneButtonH: CGFloat = 30.8
    
    /** 导航工具栏返回按钮图标显示圆边 及 星(star)样式显示圆边*/
    var isShowBorder: Bool = false
    
    /** 分多次选择照片时,剩余照片达到上限时的提示文字*/
    var leftTitle = "剩余"
    
    /** 相册类型界面的标题*/
    var albumTitle = "照片"
    
    /** 确定按钮的标题*/
    var confirmTitle  = "确定"
    
    /** 选择数量达到上限时的提示文字, #为占位符*/
    var errorImageMaxSelect = "图片选择最多不能超过#张"
    
    /** 拍摄标题*/
    var cameraTitle = "拍摄"
    
    /** 选择标题*/
    var selectTitle = "从手机相册选择"
    
    /** 取消标题*/
    var cancelTitle = "取消"
    
    /** 选择时显示的数字的字体大小等*/
    var fontSize: CGFloat = 15.0
    
    /** 预览照片的最大宽度*/
    var previewImageFetchMaxW:CGFloat = 600
    
    /** 工具栏的背景色,有透明部分则全屏穿透效果*/
    var barBGColor = UIColor(red: 40/255, green: 40/255, blue: 40/255, alpha: 0.9)
    
    /** 选择框 、按钮的颜色*/
    var tinColor = UIColor(red: 7/255, green: 179/255, blue: 20/255, alpha: 1)
    
    /** 删除按钮的颜色*/
    var removeHighlightedColor: UIColor = .red
    
    /** 删除按钮是否隐藏*/
    var isRemoveButtonHidden: Bool = false
    
    /** 按钮无效时的文字颜色*/
    var disabledColor: UIColor = .gray
    
    /** 最大照片选择数量上限*/
    var maxImageCount: Int = 9
    
    /** 压缩比,0(most)..1(least) 越小图片就越小*/
    var compressionQuality: CGFloat = 0.5
使用链式编程配置时,请在所有属性前加tg_前缀即可



选择指示器各状态组合参数说明(选择类型checkboxType、大小checkboxCellWH、位置checkboxPosition各状态下都起作用,其他配置参数起作用时机见下表(最佳快速上手请使用官方Demo进行参数调配,参数效果立竿见影))

checkbox配置
类型 未选择状态 选择状态 删除状态 删除高亮状态 数字选中状态 备注
只有勾 勾色white(0.7)、checkboxLineW 勾色tincolor、checkboxLineW 叉色同左 叉色removeHighlightedColor shadowW、shadowH、fontSize、checkboxLineW、checkboxPadding、字色tinColor  
圈勾 圈色white(0.3)、border色white(0.7)、勾色white、checkboxLineW、checkboxPadding 圈色tincolor、勾色white,checkboxLineW、渐变(checkboxBeginngAlpha、checkboxEndingAlpha)、 checkboxPadding 叉色同左 叉色removeHighlightedColor 字色white、圈色tinColor、checkboxPadding 微博未选择状态勾色clear、微博删除状态叉色white
方勾 方色white(0.3)、勾色white、checkboxLineW、checkboxCorner 方色tincolor、渐变(checkboxBeginngAlpha、checkboxEndingAlpha)、勾色white、checkboxCorner、checkboxLineW 叉色同左 叉色removeHighlightedColor 字色white、方色tinColor、checkboxCorner  
带勾 带色white(0.3)、勾色white、渐变(checkboxBeginngAlpha、0.01)、checkboxLineW、checkboxCorner、checkboxPadding 带色tincolor、勾色white、 渐变(checkboxBeginngAlpha、0.01)、 checkboxCorner、checkboxPadding、checkboxLineW 叉色同左 叉色removeHighlightedColor 字色white、方色tinColor(渐变(checkboxBeginngAlpha、0.01))、checkboxCorner  
斜带勾 带色white(0.3)、勾色white、checkboxLineW 带色tincolor、勾色white、checkboxLineW 叉色同左 叉色removeHighlightedColor 底色tinColor、字色white  
三角勾 角色white(0.3)、勾色white、checkboxLineW 角色tincolor、勾色white、checkboxLineW 叉色同左 叉色removeHighlightedColor 底色tinColor、字色white  
心色white(0.7)、checkboxLineW、无勾 心色tincolor、无勾 叉色同左、removeType为circle 叉色removeHighlightedColor 同circle  
星色white(0.3)、border色white(0.7)、isShowBorder、checkboxLineW、无勾 星色tincolor、无勾、无border 叉色同左、removeType为circle 叉色removeHighlightedColor 同circle  


更多使用配置组合效果请download本项目或fork本项目查看



ScreenShots


1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19

运行效果见https://github.com/targetcloud/TGPhotoPicker



Installation


下载并拖动TGPhotoPicker到你的工程中


Cocoapods
pod 'TGPhotoPicker'


Reference
http://blog.csdn.net/callzjy
https://github.com/targetcloud/TGImage 



如果你觉得赞,请Star点击打开链接









2016-10-12 17:04:03 WUYANYANstrong 阅读数 2455
1.首先,swift3.0中调用相机和相册会导致崩溃,需要在info.plist文件中加入两个键值对,如下:

Privacy - Photo Library Usage Description  和 Privacy - Camera Usage Description ,都是String类型,内容任意的字符串即可。

2.UIImagePickerControllerDelegate,UINavigationControllerDelegate

3.//底部弹窗

    func popupView(){

        var alert: UIAlertController!

        alert = UIAlertController(title: "提示", message: "添加照片", preferredStyle: UIAlertControllerStyle.actionSheet)

        let cleanAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel,handler:nil)

        let photoAction = UIAlertAction(title: "拍照", style: UIAlertActionStyle.default){ (action:UIAlertAction)in

            self.camera()

        }

        let choseAction = UIAlertAction(title: "从手机相册选择", style: UIAlertActionStyle.default){ (action:UIAlertAction)in

            self.photo()

        }


        alert.addAction(cleanAction)

        alert.addAction(photoAction)

        alert.addAction(choseAction)

        self.present(alert, animated: true, completion: nil)

    }

    //调用照相机方法

    func camera(){

        let pick:UIImagePickerController = UIImagePickerController()

        pick.delegate = self

        pick.sourceType = UIImagePickerControllerSourceType.camera

        self.present(pick, animated: true, completion: nil)

    }

    //调用照片方法


    func photo(){

        let pick:UIImagePickerController = UIImagePickerController()

        pick.delegate = self

        pick.sourceType = UIImagePickerControllerSourceType.photoLibrary

        self.present(pick, animated: true, completion: nil)

        

    }


swift头像上传(1)

阅读数 535

没有更多推荐了,返回首页