花了两天半的时间基本实现了APP中让用户选择头像的功能(仿照手机版QQ),整理和总结如下——
思路
- UIImagePickerController
原先想要采用UIImagePickerController来实现这个功能,UIImagePickerController是UINavigationController的子类,是系统提供的拍摄、选择照片和视频的UI。具体来说,在选择头像这个功能中,头像的来源有两种——拍照和从相册选择,同时完成头像的选择后我们还应该能够让用户选择头像的范围以及大小。
若头像的来源为拍照:
1 | UIImagePickerController * imagePickerController = [[UIImagePickerController alloc]init]; |
同时,实现UIImagePickerDelegate中的如下方法:
1 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { |
如果头像的来源为相册,则只需修改imagePickerController的sourceType属性即可:
`imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;`
这样做就可以实现我们的需求了,但是这个方法的缺点也很明显,在这个方法中,我们使用的是系统封装好的UI,参考手机版QQ的选择头像我们可以发现,我们不能自定义相册中图片的分类、排版。同样的,我们也不能自定义编辑头像的界面,你不能将正方形的头像选框改成圆形的。因此,我们需要自己实现一个“UIImagePickerController”。在这个UIImagePickerController中,除了图片来源为拍照的情况下我们采用系统原生的UIImagePickerController以外,编辑图片和从相册中选取图片的功能我们都自己实现。
- PhotoKit和UICollectionView
对于从相册选择图片的功能,我们可以采用PhotoKit来获取到图片的信息,并通过UICollectionView加以展示,这里主要给出PhotoKit的代码:
1 | #import <Photos/Photos.h> |
- 自定义编辑头像的界面
主要有两个方面
- 展示图片 我采用的方法是向一个UIScrollView中添加一个UIImageView
- 圆形选框 采用了两个CAShapeLayer,一个是选框的Layer,另一个是遮罩的Layer
实现展示图片的功能首先需要了解UIScrollView中frame,contentSize和contentOffset的区别。同时,为了将图片限制在我们所画的边框内,关键是设置合理的minimumZoomScale(最小缩放比例)以及实时更新ContentSize,代码如下:
1 | - (void)imageConfiguration { |
圆形选框则比较简单,用一个CAShapeLayer即可实现,实现阴影遮罩(效果可以参考手机版QQ)则需要另一个CAShapeLayer,这里有一个问题,如果直接把遮罩设在self.view上,将会在页面切换的时候造成动画的不自然,我的解决方法是在self.view上添加一个UIView的实例contentView作为容器,代码如下:
1 | self.contentView.layer.mask = self.maskLayer; |
问题
- 修改导航栏的高度
1 | - (void)viewWillAppear:(BOOL)animated { |
- 调整导航栏中Title和Button的垂直位置
Title:
1 | - (void)viewWillAppear:(BOOL)animated { |
Button:
1 | [self.barButtonItem setBackgroundVerticalPositionAdjustment:-10.0 forBarMetrics:UIBarMetricsDefault]; |
- 隐藏状态栏
1 | - (BOOL)prefersStatusBarHidden { |
- UIScrollView不能缩放
需要实现代理方法- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
指定需要缩放的子控件
- 截取缩放过的UIImageView中的特定位置和大小的图片
1 | - (UIImage *)imageWithZoomScale:(CGFloat)zoomScale { |