美文网首页iOS DeveloperiOS工程实践IOS
iOS实现头像裁剪( 方或圆)功能,支持缩放拖拽。

iOS实现头像裁剪( 方或圆)功能,支持缩放拖拽。

作者: 倾世圣伊 | 来源:发表于2017-01-10 23:04 被阅读1742次
    类似微信头像选择裁剪功能 ,设置UIImagePickerController的allowsEditing属性为YES即可实现,但如何自己实现此功能呢?如何实现类似系统联系人圆形头像裁剪选取呢?

    如图:


    Simulator Screen Shot 00.png
    图片要支持缩放和拖拽,首先想到scrollView,具体实现方法如下:
    //CropImageController.h
    @protocol CropImageDelegate <NSObject>
    - (void)cropImageDidFinishedWithImage:(UIImage *)image;
    @end
    
    @interface CropImageController : UIViewController
    
    @property (nonatomic, weak) id <CropImageDelegate> delegate;
    //圆形裁剪,默认NO;
    @property (nonatomic, assign) BOOL ovalClip;
    - (instancetype)initWithImage:(UIImage *)originalImage delegate:(id)delegate;
    @end
    

    在viewDidLoad初始化scrollView,设置frame为裁剪框大小,若需要超出边界线内容仍然可以显示,设置其layer属性masksToBounds即可

    - (void)viewDidLoad {
        [super viewDidLoad];
    // Do any additional setup after loading the view.
        self.view.backgroundColor = [UIColor blackColor];
        self.automaticallyAdjustsScrollViewInsets = NO;
        CGFloat height = (ScreenHeight - ScreenWidth)/2.0;
        _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, height ,ScreenWidth,ScreenWidth)];
        _scrollView.bouncesZoom = YES;
        _scrollView.minimumZoomScale = 1;
        _scrollView.maximumZoomScale = 3;
        _scrollView.zoomScale = 1;
        _scrollView.delegate = self;
        _scrollView.layer.masksToBounds = NO;
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.showsVerticalScrollIndicator = NO;
        _scrollView.layer.borderWidth = 1.5;
        _scrollView.layer.borderColor = [UIColor whiteColor].CGColor;
          if (_ovalClip) {
            _scrollView.layer.cornerRadius = ScreenWidth/2.0;
        }
        self.view.layer.masksToBounds = YES;
        if (_originalImage) {
            _imageView = [[UIImageView alloc] initWithImage:_originalImage];
            CGFloat img_width = ScreenWidth;
            CGFloat img_height = _originalImage.size.height * (img_width/_originalImage.size.width);
            CGFloat img_y= (img_height - self.view.bounds.size.width)/2.0;
            _imageView.frame = CGRectMake(0,0, img_width, img_height);
            _imageView.userInteractionEnabled = YES;
            [_scrollView addSubview:_imageView];
            
            
            _scrollView.contentSize = CGSizeMake(img_width, img_height);
            _scrollView.contentOffset = CGPointMake(0, img_y);
            [self.view addSubview:_scrollView];
        }
        [self userInterface];
    }
    

    设置self.view中间镂空效果:

    - (void)userInterface {
        
        CGRect cropframe = _scrollView.frame;
        UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:self.view.bounds cornerRadius:0];
        UIBezierPath * cropPath = [UIBezierPath bezierPathWithRoundedRect:cropframe cornerRadius:0];
        if (_ovalClip) {
            cropPath = [UIBezierPath bezierPathWithOvalInRect:cropframe];
        }
        [path appendPath:cropPath];
        
        CAShapeLayer * layer = [[CAShapeLayer alloc] init];
        layer.fillColor = [UIColor colorWithRed:.0 green:.0 blue:.0 alpha:0.5].CGColor;
        //填充规则
        layer.fillRule=kCAFillRuleEvenOdd;
        layer.path = path.CGPath;
        [self.view.layer addSublayer:layer];
    }
    

    UIScrollViewDelegate,缩放和滑动过程中调整内容视图大小:

    #pragma mark -- UIScrollViewDelegate
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
        return self.imageView;
    }
    - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
        //调整位置
        [self centerContent];
    }
    - (void)centerContent {
        CGRect imageViewFrame = _imageView.frame;
        
        CGRect scrollBounds = CGRectMake(0, 0, ScreenWidth, ScreenWidth);
        if (imageViewFrame.size.height > scrollBounds.size.height) {
            imageViewFrame.origin.y = 0.0f;
        }else {
            imageViewFrame.origin.y = (scrollBounds.size.height - imageViewFrame.size.height) / 2.0;
        }
        if (imageViewFrame.size.width < scrollBounds.size.width) {
            imageViewFrame.origin.x = (scrollBounds.size.width - imageViewFrame.size.width) /2.0;
        }else {
            imageViewFrame.origin.x = 0.0f;
        }
        _imageView.frame = imageViewFrame;
    }
    

    调整位置确定选取图片时候,可根据当前ScrollView的contentOffset和缩放倍数确定具体裁剪位置:

    - (UIImage *)cropImage {
        CGPoint offset = _scrollView.contentOffset;
        //图片缩放比例
        CGFloat zoom = _imageView.frame.size.width/_originalImage.size.width;
        //视网膜屏设备像素相关
        zoom = zoom / [UIScreen mainScreen].scale;
        
        CGFloat width = _scrollView.frame.size.width;
        CGFloat height = _scrollView.frame.size.height;
        if (_imageView.frame.size.height < _scrollView.frame.size.height) {//太胖了,取中间部分
            offset = CGPointMake(offset.x + (width - _imageView.frame.size.height)/2.0, 0);
            width = height = _imageView.frame.size.height;
        }
        
        CGRect rec = CGRectMake(offset.x/zoom, offset.y/zoom,width/zoom,height/zoom);
        CGImageRef imageRef =CGImageCreateWithImageInRect([_originalImage CGImage],rec);
        UIImage * image = [[UIImage alloc]initWithCGImage:imageRef];
        CGImageRelease(imageRef);
        if (_ovalClip) {
            image = [image ovalClip];
        }
        return image;
    }
    

    UIImage分类(图片指定尺寸缩放和圆形裁剪):

    //UIImage+Crop.m
    - (UIImage *)resizeImageWithSize:(CGSize)newSize {
        CGFloat newWidth = newSize.width;
        CGFloat newHeight = newSize.height;
        float width  = self.size.width;
        float height = self.size.height;
        if (width != newWidth || height != newHeight) {
            UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), YES, [UIScreen mainScreen].scale);
            [self drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
            
            UIImage *resized = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            return resized;
        }
        return self;
    }
    - (UIImage *)ovalClip {
    
        CGSize size = self.size;
        UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
        UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
        [path addClip];
        [self drawAtPoint:CGPointZero];
        UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return image;
    }
    

    注:由于对图片进行裁剪,先将原始图片等比缩放到指定裁剪宽度。
    源码下载

    相关文章

      网友评论

        本文标题:iOS实现头像裁剪( 方或圆)功能,支持缩放拖拽。

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