本文简单分析下 ZLPhotoBrowser 的源代码,
其中的图片旋转,使用的是 ZLClipImageViewController
ZLPhotoBrowser 代码比较绕,很有意思
特色:
大部分封装的功能控制器,使用的入口是 ZLPhotoPreviewSheet
例外:
图片预览控制器, 使用 ZLImagePreviewController,可方便地直接调用
照相机,使用 ZLCustomCamera,可方便地直接调用
1.1 , 图片旋转控制器的官方调用流程
先进入预览界面
ZLPhotoPreviewSheet 类里面,
func showPreviewController(_ models: [ZLPhotoModel], index: Int) {
let vc = ZLPhotoPreviewController(photos: models, index: index)
let nav = self.getImageNav(rootViewController: vc)
// ...
self.sender?.showDetailViewController(nav, sender: nil)
}
预览界面,进入编辑界面, ZLEditImageViewController
func showEditImageVC(image: UIImage) {
let model = self.arrDataSources[self.currentIndex]
let nav = self.navigationController as! ZLImageNavController
ZLEditImageViewController.showEditImageVC(parentVC: self, image: image, editModel: model.editImageModel) { [weak self, weak nav] (ei, editImageModel) in
// ...
}
}
编辑界面, 进入旋转界面 ZLClipImageViewController
1.1.1 , 预览界面,进入旋转界面, ZLClipImageViewController
简单调整下,官方的代码
ZLEditImageViewController 类里面,
@objc public class func showEditImageVC(parentVC: UIViewController?, animate: Bool = false, image: UIImage, editModel: ZLEditImageModel? = nil, completionX: ( (UIImage, ZLEditImageModel?) -> Void )? ) {
let vc = ZLClipImageViewController(image: image, editRect: editModel?.editRect, angle: editModel?.angle ?? 0, selectRatio: editModel?.selectRatio)
// ...
vc.animate = animate
vc.modalPresentationStyle = .fullScreen
parentVC?.present(vc, animated: animate, completion: nil)
}
ZLPhotoBrowser的这段逻辑,很有特色
ZLEditImageViewController 什么用,都没有
只是简单的中转一下
1.2 , 直接去编辑控制器
ZLPhotoPreviewSheet 类里面,
稍微调整下
点击 demo 的 ViewController 的,中间的列表的 item
@objc public func previewAssets(sender: UIViewController, assets: [PHAsset], index: Int, isOriginal: Bool, showBottomViewAndSelectBtn: Bool = true) {
let models = assets.removeDuplicate().map { (asset) -> ZLPhotoModel in
let m = ZLPhotoModel(asset: asset)
m.isSelected = true
return m
}
self.arrSelectedModels.removeAll()
self.arrSelectedModels.append(contentsOf: models)
self.sender = sender
self.isSelectOriginal = isOriginal
self.isHidden = true
self.sender?.view.addSubview(self)
if arrSelectedModels.count > 0{
shouldDirectEdit(arrSelectedModels[0])
}
}
进入 ZLEditImageViewController
func shouldDirectEdit(_ model: ZLPhotoModel) -> Bool {
self.showEditImageVC(model: model)
return false
}
1.2.1 , 直接去, 图片旋转控制器
稍微调整下,上面的代码
直接去 ZLClipImageViewController
func showEditImageVC(model: ZLPhotoModel) {
ZLPhotoManager.fetchImage(for: model.asset, size: model.previewSize) { [weak self] (image, isDegraded) in
if let image = image {
let editModel = model.editImageModel
let vc = ZLClipImageViewController(image: image, editRect: editModel?.editRect, angle: editModel?.angle ?? 0)
vc.clipDoneBlockZz = { [weak self] (angle) in
let ei = image.clipImage(angle) ?? image
let editImageModel = ZLEditImageModel(editRect: CGRect.zero, angle: angle)
model.isSelected = true
model.editImage = ei
model.editImageModel = editImageModel
self?.arrSelectedModels.append(model)
self?.requestSelectPhoto()
}
vc.modalPresentationStyle = .fullScreen
self?.sender?.present(vc, animated: true, completion: nil)
}
// ...
}
}
图片旋转分析
ZLClipImageViewController 控制器的
func rotateBtnClick() 方法中,
每一次旋转,都把数据给修改了
self.editImage = self.editImage.rotate(orientation: .left)
// ...
self.imageView.image = self.editImage
这里的处理,比较重,
常用思路,可以记录旋转的角度,设置 imageView 的 transfrom
需要的时候,再修改数据
优点: 伪动画
这里的旋转,是改图片数据,重新布局
还创建一个临时的 imageView ,做动画
let transform = CGAffineTransform(rotationAngle: -CGFloat.pi/2)
let animateImageView = UIImageView(image: self.editImage)
animateImageView.contentMode = .scaleAspectFit
animateImageView.clipsToBounds = true
view.addSubview(animateImageView)
self.containerView.alpha = 0
UIView.animate(withDuration: 0.3, animations: {
animateImageView.transform = transform
animateImageView.frame = toFrame
}) { (_) in
animateImageView.removeFromSuperview()
self.containerView.alpha = 1
}
滚动视图代理方法,用的好
func viewForZooming(in scrollView: UIScrollView) -> UIView?
可优化
各种布局计算,七算八算,绕
没有利用到,AVFoundation 的 AVMakeRect 方法