美文网首页iOS高质量博客UI进价iOS点点滴滴
iOS-拍照后裁剪,不可拖动照片的问题

iOS-拍照后裁剪,不可拖动照片的问题

作者: jins_1990 | 来源:发表于2016-07-08 15:04 被阅读3331次

    问题

    在项目中,选择照片或拍照的功能很长见,由于我之前采用系统自带的UIimagePickViewController遇到一点问题:

    • 使用拍照功能,进行截取时(allowEditing = YES)时,拍照完成的图片无法拖动,没有办法进行选择性的截取图片
    • 如果使用选择相册功能,进入裁剪界面,图片是可以拖动的,唯独拍照之后进入裁剪界面无法拖动
    • 微信头像更换拍照好像也无法拖动,初步推测可能使用的系统自带的裁剪界面
      所以想来仔细研究一下UIImagePickViewController的属性和使用方法

    UIImagePickViewController

    UIImagePickerController是iOS系统提供的和系统的相册和相机交互的一个类,可以用来获取相册的照片,也可以调用系统的相机拍摄照片或者视频。该类的继承结构是:

    UIImagePickerController-->UINavigationController-->UIViewController-->UIResponder-->NSObject

    官方文档中对于该类的说明是:

    该类只支持竖屏模式,为了保证该类被原样使用,它不支持子类,并且它的视图层次是私有的不能被修改,只支持自定义cameraOverlayView属性来展示更多信息以及和用户的交互。

    由于该类继承自UINavgationController,所以在使用过程中一般实现UIImagePickerControllerDelegateUINavigationControllerDelegate这两个代理,可以利用navgation的push 和pop操作自定义界面实现更复杂的交互效果。

    下面具体分析该类的一些方法和属性.

    UIImagePickViewController之常用属性

    @property (nullable, nonatomic, weak) id <UINavigationControllerDelegate, UIImagePickerControllerDelegate> delegate;
    

    该对象的代理需要实现UINavigationControllerDelegateUIImagePickerControllerDelegate协议,nullable是xcode6.3之后引入的nullability annotations特性,主要用于在OC和swift之间的转换。这一特性主要包含两个新的类型注释nullablenonnull,用于表示对象是否可以是NULLnil

    @property (nonatomic) UIImagePickerControllerSourceType sourceType; // default value is UIImagePickerControllerSourceTypePhotoLibrary.
    

    sourceType用于指定要访问的系统的媒体类型。UIImagePickerControllerSourceType支持以下3种枚举类型,默认值是图片库

    typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) { UIImagePickerControllerSourceTypePhotoLibrary,//照片库模式。图像选取控制器以该模式显示时会浏览系统照片库的根目录。 UIImagePickerControllerSourceTypeCamera, //相机模式,图像选取控制器以该模式显示时可以进行拍照或摄像。 UIImagePickerControllerSourceTypeSavedPhotosAlbum //相机胶卷模式,图像选取控制器以该模式显示时会浏览相机胶卷目录。};
    
    • PhotoLibrary代表系统照片应用对应的相薄,包含照片流和其它自定义的相册
    • PhotosAlbum则对应系统照片应用的照片,包含用设备拍摄的所有照片流。
    • Camera则代表相机的摄像头。
    @property (nonatomic, copy) NSArray<NSString *> *mediaTypes;
    

    mediaTypes用于设置相机支持的功能,拍照或者是视频,返回值类型可以是kUTTypeMovie视频和kUTTypeImage拍照

    • kUTTypeMovie包含
    const CFStringRef kUTTypeAudiovisualContent ;抽象的声音视频
    const CFStringRef kUTTypeMovie ;抽象的媒体格式(声音和视频)
    const CFStringRef kUTTypeVideo ;只有视频没有声音
    const CFStringRef kUTTypeAudio ;只有声音没有视频
    const CFStringRef kUTTypeQuickTimeMovie ;
    const CFStringRef kUTTypeMPEG ;
    const CFStringRef kUTTypeMPEG4 ;
    const CFStringRef kUTTypeMP3 ;
    const CFStringRef kUTTypeMPEG4Audio ;
    const CFStringRef kUTTypeAppleProtectedMPEG4Audio;
    
    • kUTTypeImage包含
    const CFStringRef kUTTypeImage ;抽象的图片类型
    const CFStringRef kUTTypeJPEG ;
    const CFStringRef kUTTypeJPEG2000 ;
    const CFStringRef kUTTypeTIFF ;
    const CFStringRef kUTTypePICT ;
    const CFStringRef kUTTypeGIF ;
    const CFStringRef kUTTypePNG ;
    const CFStringRef kUTTypeQuickTimeImage ;
    const CFStringRef kUTTypeAppleICNS const CFStringRef kUTTypeBMP;
    const CFStringRef kUTTypeICO;
    

    @property (nonatomic) BOOL showsCameraControls NS_AVAILABLE_IOS(3_1);
    @property (nonatomic) BOOL allowsEditing NS_AVAILABLE_IOS(3_1); // replacement for -allowsImageEditing; default value is NO.
    @property (nonatomic) BOOL allowsImageEditing NS_DEPRECATED_IOS(2_0, 3_1);
    
    • showsCameraControls用于指定拍照时下方的工具栏是否显示
    • allowImageEditing在iOS3.1就已废弃,取而代之的是allowEditing,
    • allowEditing表示拍完照片或者从相册选完照片后,是否跳转到编辑模式对图片裁剪,只有在showsCameraControls为YES时才有效果。

    @property (nonatomic) UIImagePickerControllerCameraCaptureMode cameraCaptureMode NS_AVAILABLE_IOS(4_0); // default is UIImagePickerControllerCameraCaptureModePhoto
    @property (nonatomic) UIImagePickerControllerCameraDevice cameraDevice NS_AVAILABLE_IOS(4_0); // default is UIImagePickerControllerCameraDeviceRear
    @property (nonatomic) UIImagePickerControllerCameraFlashMode cameraFlashMode 
    @property (nonatomic) CGAffineTransform cameraViewTransform NS_AVAILABLE_IOS(3_1); // set the transform of the preview view.
    @property (nullable, nonatomic,strong) __kindof UIView *cameraOverlayView NS_AVAILABLE_IOS(3_1); // set a view to overlay the preview view.
    

    sourceTypecamera的时候,这几个属性有效,否则抛出异常。

    • cameraCaptureMode捕捉模式指定的是相机是拍摄照片还是视频,它的枚举类型如下:
    NS_ENUM(NSInteger, UIImagePickerControllerCameraCaptureMode) { 
        UIImagePickerControllerCameraCaptureModePhoto,//photo 
        UIImagePickerControllerCameraCaptureModeVideo//video
    };
    
    • cameraDevice指定拍摄的摄像头位置,是使用前置摄像头还是后置摄像头,它的枚举类型有:
    typedef NS_ENUM(NSInteger, UIImagePickerControllerCameraDevice) { 
        UIImagePickerControllerCameraDeviceRear,//后摄像头(默认) 
        UIImagePickerControllerCameraDeviceFront//前摄像头
    };
    
    • cameraFlashMode用于指定闪光灯模式,它的枚举类型如下:
    typedef NS_ENUM(NSInteger, UIImagePickerControllerCameraFlashMode) { 
        UIImagePickerControllerCameraFlashModeOff = -1,//关闭闪关灯 
        UIImagePickerControllerCameraFlashModeAuto = 0,//自动 
        UIImagePickerControllerCameraFlashModeOn = 1//开启闪关灯
    };
    
    • cameraViewTransform该结构体可以用于指定拍摄时View的一些形变属性,如旋转缩放等。当showsCameraControls为NO,系统的工具栏隐藏时,我们可以自定义背景View赋值给cameraOverlayView添加到拍摄时的预览视图之上。

    @property(nonatomic) NSTimeInterval videoMaximumDuration NS_AVAILABLE_IOS(3_1); // default value is 10 minutes.
    @property(nonatomic) UIImagePickerControllerQualityType videoQuality NS_AVAILABLE_IOS(3_1);
    
    • videoMaximumDuration用于设置视频拍摄模式下最大拍摄时长,默认值是10分钟。
    • videoQuality表示拍摄的视频质量设置,默认是Medium即表示中等质量。 videoQuality支持的枚举类型如下:
    typedef NS_ENUM(NSInteger, UIImagePickerControllerQualityType) { 
        UIImagePickerControllerQualityTypeHigh = 0, // 高清模式 
        UIImagePickerControllerQualityTypeMedium = 1, //中等质量,适于WIFI传播
        UIImagePickerControllerQualityTypeLow = 2, //低等质量,适于蜂窝网络传输 
        UIImagePickerControllerQualityType640x480 NS_ENUM_AVAILABLE_IOS(4_0) = 3, // VGA 质量 
        UIImagePickerControllerQualityTypeIFrame1280x720 NS_ENUM_AVAILABLE_IOS(5_0) = 4,//1280*720的分辨率 
        UIImagePickerControllerQualityTypeIFrame960x540 NS_ENUM_AVAILABLE_IOS(5_0) = 5,//960*540分辨率
    };
    

    UIImagePickViewController之类方法

    @interface UIImagePickerController : UINavigationController <NSCoding>
    + (BOOL)isSourceTypeAvailable:(UIImagePickerControllerSourceType)sourceType; // returns YES if source is available (i.e. camera present)
    + (nullable NSArray<NSString *> *)availableMediaTypesForSourceType:(UIImagePickerControllerSourceType)sourceType; // returns array of available media types (i.e. kUTTypeImage)
    + (BOOL)isCameraDeviceAvailable:(UIImagePickerControllerCameraDevice)cameraDevice NS_AVAILABLE_IOS(4_0); // returns YES if camera device is available 
    + (BOOL)isFlashAvailableForCameraDevice:(UIImagePickerControllerCameraDevice)cameraDevice NS_AVAILABLE_IOS(4_0); // returns YES if camera device supports flash and torch.
    + (nullable NSArray<NSNumber *> *)availableCaptureModesForCameraDevice:(UIImagePickerControllerCameraDevice)cameraDevice NS_AVAILABLE_IOS(4_0);
    
    • isSourceTypeAvailable用于判断当前设备是否支持指定的sourceType,可以是照片库/相册/相机.
    • isCameraDeviceAvailable判断当前设备是否支持前置摄像头或者后置摄像头
    • isFlashAvailableForCameraDevice是否支持前置摄像头闪光灯或者后置摄像头闪光灯
    • availableMediaTypesForSourceType方法返回所特定的媒体如相册/图片库/相机所支持的媒体类型数组,元素值可以是kUTTypeImage类型或者kUTTypeMovie类型的静态字符串,所以是NSString类型的数组
    • availableCaptureModesForCameraDevice返回特定的摄像头(前置摄像头/后置摄像头)所支持的拍摄模式数值数组,元素值可以是UIImagePickerControllerCameraCaptureMode枚举里面的video或者photo,所以是NSNumber类型的数组

    UIImagePickViewController之对象方法

    - (void)takePicture NS_AVAILABLE_IOS(3_1);
    - (BOOL)startVideoCapture NS_AVAILABLE_IOS(4_0);
    - (void)stopVideoCapture NS_AVAILABLE_IOS(4_0);
    
    • takePicture可以用来实现照片的连续拍摄,需要自己自定义拍摄的背景视图来赋值给cameraOverlayView,结合自定义overlayView实现多张照片的采集,在收到代理的didFinishPickingMediaWithInfo方法之后可以启动额外的捕捉。
    • startVideoCapture用来判断当前是否可以开始录制视频,当视频正在拍摄中,设备不支持视频拍摄,磁盘空间不足等情况,该方法会返回NO.该方法结合自定义overlayView可以拍摄多部视频
    • stopVideoCapture当你调用此方法停止视频拍摄时,它会调用代理的imagePickerController:didFinishPickingMediaWithInfo:方法

    UIImagePickViewController之代理方法

    @protocol UIImagePickerControllerDelegate<NSObject>
    @optional
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo NS_DEPRECATED_IOS(2_0, 3_0);
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
    @end
    
    • imagePickerController:didFinishPickingImage:editingInfo:在iOS3.0中已废弃,不再使用。
    • 当用户取消选取的内容时会调用DidCancel方法,默认实现销毁弹出的视图。
    • 当完成内容的选取时会调用didFinishPickingMediaWithInfo方法,默认info字典的key值可以是以下类型:
    UIKIT_EXTERN NSString *const UIImagePickerControllerMediaType; //指定用户选择的媒体类型
    UIKIT_EXTERN NSString *const UIImagePickerControllerOriginalImage; // 原始图片
    UIKIT_EXTERN NSString *const UIImagePickerControllerEditedImage; // 修改后的图片
    UIKIT_EXTERN NSString *const UIImagePickerControllerCropRect; // 裁剪尺寸
    UIKIT_EXTERN NSString *const UIImagePickerControllerMediaURL; // 媒体的URL
    UIKIT_EXTERN NSString *const UIImagePickerControllerReferenceURL NS_AVAILABLE_IOS(4_1); // 原件的URL
    UIKIT_EXTERN NSString *const UIImagePickerControllerMediaMetadata //当数据来源是相机的时候获取到的静态图像元数据,可以使用phtoho框架进行处理
    

    UIImagePickViewController之C语言函数(保存图片或视频)

    UIKIT_EXTERN void UIImageWriteToSavedPhotosAlbum(UIImage *image, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo);
    UIKIT_EXTERN BOOL UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(NSString *videoPath) NS_AVAILABLE_IOS(3_1);
    UIKIT_EXTERN void UISaveVideoAtPathToSavedPhotosAlbum(NSString *videoPath, __nullable id completionTarget, __nullable SEL completionSelector, void * __nullable contextInfo) NS_AVAILABLE_IOS(3_1);
    
    • UIImageWriteToSavedPhotosAlbum用来保存照片到相册,seletor应该设置为- (void)image:(UIImage )image didFinishSavingWithError:(NSError )error contextInfo:(void )contextInfo;当照片保存到相册完成时,会调用该方法通知你。
    • UIVideoAtPathIsCompatibleWithSavedPhotosAlbum会返回布尔类型的值判断该路径下的视频能否保存到相册,视频需要先存储到沙盒文件再保存到相册,而照片是可以直接从代理完成的回调info字典里面获取到。
    • UISaveVideoAtPathToSavedPhotosAlbum用来保存视频到相册,seletor应该设置为- (void)video:(NSString )videoPath didFinishSavingWithError:(NSError )error contextInfo:(void )contextInfo;当视频保存到相册或出错时会调用该方法通知你。
      这三个方法一般是在代理的完成方法didFinishPickingMediaWithInfo里面配合使用。

    以上便是系统UIImagePickViewController的所有属性和方法的简单介绍


    问题解决方案

    由于使用设置allowEditing = YES属性后,开启摄像头拍照后直接进入系统自定义的裁剪界面,但是在这个界面,从摄像头拍摄过来的照片无法拖动裁剪,仅仅从相册选择过来的照片是可以拖动进行裁剪的,那么我们就决定裁剪界面不使用系统自带的,而自定义一个裁剪界面.

    在UIImagePickViewController的代理方法里

    #pragma UIImagePickerController Delegate
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
      UIImage *portraitImg = [info objectForKey:@"UIImagePickerControllerOriginalImage"]; 
      YYImageClipViewController *imgClipVC = [[YYImageClipViewController alloc] initWithImage:portraitImg cropFrame:CGRectMake(0, 100.0f, self.view.frame.size.width, self.view.frame.size.width) limitScaleRatio:3.0]; 
      imgClipVC.delegate = self;
      [picker pushViewController:imgClipVC animated:NO];
    }
    
    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
    { 
      [picker dismissViewControllerAnimated:YES completion:nil];
    }
    

    HZImageCropperViewController是我自定义的一个裁剪界面,通过这个控制器的两个代理方法,得到裁剪后的照片

    - (void)imageClip:(YYImageClipViewController *)clipViewController didFinished:(UIImage *)editedImage 
    { 
      //保存图片
      NSString *imageFilePath = [UIImage saveImage:editedImage]; 
      //上传七牛服务器 
      [self upImageFilePath:imageFilePath]; 
      //隐藏裁剪界面 
      [clipViewController dismissViewControllerAnimated:YES completion:nil];
    }
    
    - (void)imageClipDidCancel:(YYImageClipViewController *)clipViewController
    {
       [clipViewController dismissViewControllerAnimated:YES completion:nil];
    }
    

    下面附上一个demo,里面包含裁剪界面的源代码,可供大家参考
    自定义裁剪界面demo

    相关文章

      网友评论

      • 宋鸿康iOS:厉害,刚好工作有用到:+1:
      • 哇哇卡:保存图片方法:saveImage:的方法是怎么保存的,保存前有做压缩等处理么?
      • 哇哇卡:请问打开拍照功能,放大之后,再点拍照,发送图片会崩溃么?
      • 素酥:比例已经调好。。现在差涂鸦了求教
      • 素酥:还有想请问下。。那个系统自带的裁剪界面。。截图是1:1的如何把他变成3:4的。。请教。。。有点急。。。在线等
      • 素酥:你好。。请问下是如何加涂鸦的..

      本文标题:iOS-拍照后裁剪,不可拖动照片的问题

      本文链接:https://www.haomeiwen.com/subject/koqrjttx.html