美文网首页
iOS 九宫格切图功能实现

iOS 九宫格切图功能实现

作者: 宏炜 | 来源:发表于2022-02-18 11:33 被阅读0次
    image.png

    如上图所示,完成如上功能。下面主要介绍下功能的实现:

    一: 编辑页面

    1: UI布局
    布局较为简单,就不详细阐述了,只说下注意点。因为图片需要滑动,所以图片是加在UIScrollView上的。例如九宫格的布局,scrollView宽高是屏幕的宽度,例如在iphone7中,宽高都是375,那么Imageview的宽高是否也和scrollView一样等于375呢,看起来是相等的,实则不然,因为Imageview是需要滑动的,如果相等,scrollView的contentSize如果大于Imageview的宽高,scrollView滑动过后,就会出现空白的区域。所以Imageview的宽高应该等于scrollView的contentSize的大小,至于contentSize的大小怎么计算,在下面的操作逻辑中会写到!

    2: 操作逻辑
    (1 ) 用户可向上下左右四个方向滑动图片,来调整图片位置
    注意:图片上下左右需要滑动多少,由图片的原始宽度和原始高度决定,根据图片的原始宽高算出scrollView的contentSize,contentSize就是图片能够滑动的范围,也是ImageView.frame 的 width 和height 。
    计算ImageView的宽度 (img_Width) :
    原始图片的高度除以scrollView的Frame高度,得到图片的高度比例
    原始图片的宽度除以图片的高度比例,得到ImageView需要显示的图片宽度
    计算ImageView的高度(img_Height) :
    原始图片的宽度除以scrollView的Frame宽度,得到图片的宽度比例
    原始图片的高度除以图片的宽度比例,得到ImageView需要显示的图片高度

     图片滑动范围: self.scrollView.contentSize = CGSizeMake(img_Width, img_Height);
    

    代码如下:

    //计算图片滑动范围
    -(void)setScrollviewContentOffset{
       /*
        横向的宽度等于:
           原始图片的高度除以ImageView的Frame高度,得到图片的高度比例
           原始图片的宽度除以图片的高度比例,得到ImageView需要显示的图片宽度
        */
        //_img_Width: imageview的宽度
       _img_Width = self.imageSize.width / (self.imageSize.height / self.scrollView.frame.size.height);
      
       /*
         纵向的高度等于:
           原始图片的宽度除以ImageView的Frame宽度,得到图片的宽度比例
           原始图片的高度除以图片的宽度比例,得到ImageView需要显示的图片高度
        */
          //_img_Height: imageview的高度
       _img_Height = self.imageSize.height / (self.imageSize.width /self.scrollView.frame.size.width);
    
       if (_img_Width < self.frame.size.width) {
           _img_Width = self.frame.size.width;
       }
        
       if (_img_Height < self.frame.size.height) {
           _img_Height = self.frame.size.height;
       }
      
        NSLog(@"_img_Width ==%ld, _img_Height == %ld",_img_Width,_img_Height);
       NSLog(@"imageSize.Width ==%f, imageSize.height == %f",self.imageSize.width,self.imageSize.height);
       
        //设置图片滑动范围
       self.scrollView.contentSize = CGSizeMake(_img_Width, _img_Height);
    }
    

    (2) 用户可通过双指缩放来调整图片大小
    需求中放大缩小的比例是2和1,也就是原始图片不能再缩小,最小比例是1.0
    功能实现:这里直接采用 scrollView 的 maximumZoomScale 和 minimumZoomScale 属性,设置缩放倍数。

    代码如下:

     //设置缩放倍数
        _scrollView.maximumZoomScale = 2.0;
        _scrollView.minimumZoomScale = 1.0;
        _scrollView.delegate = self;
    
    #pragma mark ============ UIScrollViewDelegate ============
    //设置需要缩放的view
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
       return self.imageView;
    }
    
    //在这个代理方法里面设置滚动范围、调整放大图片的位置,固定imageView始终在整个content的居中位置:(如果不设置,放大后图片按照原来比例frame的X,Y值也会跟随比例变化,图片就跑偏了)
    - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
        CGRect frame = self.imageView.frame;
        frame.origin.y = (self.scrollView.frame.size.height - self.imageView.frame.size.height) > 0 ? (self.scrollView.frame.size.height - self.imageView.frame.size.height) * 0.5 : 0;
        frame.origin.x = (self.scrollView.frame.size.width - self.imageView.frame.size.width) > 0 ? (self.scrollView.frame.size.width - self.imageView.frame.size.width) * 0.5 : 0;
        self.imageView.frame = frame;
        self.scrollView.contentSize = CGSizeMake(self.imageView.frame.size.width, self.imageView.frame.size.height);
    }
    
    

    (3) 完成图片操作后,点击下一步,截取图片
    刚开始做这个功能,截图一直比较模糊,是因为使用了:UIGraphicsBeginImageContext(size),
    UIGraphicsBeginImageContext(size) 等价于 UIGraphicsBeginImageContextWithOptions(size,NO,1.0)
    图片再切的时候它的scale,即缩放比率这里默认不缩放处理,那么剪切出来的图片用UI开发那边的说法即为1倍图,而我们iOS的手机现在市面上的一般都是retain屏幕,像素用一 倍图处理处理的图片当然显示出来会比较模糊。那么。我们就可以将需要切的图片的scale设置为 [UIScreen mainScreen].scale
    使用 UIGraphicsBeginImageContextWithOptions(size, YES, [UIScreen mainScreen].scale)

    代码如下:

    // 使用上下文截图,并使用指定的区域裁剪
    - (UIImage *)screenShot
    {
        // 将要被截图的view
        CGSize size = self.sudokuView.frame.size;
    
        // 开启上下文,使用参数之后,截出来的是原图(YES  0.0 质量高)
        UIGraphicsBeginImageContextWithOptions(size, YES, [UIScreen mainScreen].scale);
    
        // 裁剪的矩形范围
        CGRect rect = CGRectMake(0, 0, size.width, size.height);
        
        //注:iOS7以后renderInContext:由drawViewHierarchyInRect:afterScreenUpdates:替代
        [self.sudokuView drawViewHierarchyInRect:rect afterScreenUpdates:NO];
           
        // 从上下文中,取出UIImage
        UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
    
        //结束上下文(移除栈顶上下文)
        UIGraphicsEndImageContext();
         
        return snapshot;
    }
    

    二: 保存页面

    1: UI布局
    一张图片要切割成多张,切割后的每一张大小相等,每一张都能点击保存,所以布局用 UICollectionView
    切割的划分白线显示,设置UICollectionViewFlowLayout 的.minimumInteritemSpacing 和 minimumLineSpacing即可
    //相邻两个cell的最小间距
    layout.minimumInteritemSpacing = iPad ? 2.0 : 1.0;
    //两行之间的间距
    layout.minimumLineSpacing = iPad ? 2.0 : 1.0;
    设置背景色: self.collectionView.backgroundColor = [UIColor whiteColor];

    计算cell大小,要减去分割线的间距

    //定义每一个cell的大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
        return CGSizeMake((self.imageView.frame.size.width - (iPad ? 4:2)) / 3, (self.imageView.frame.size.width - (iPad ? 4:2)) / 3);
    }
    

    2: 图片切割功能
    图片切割,要根据三、六、九、十二宫格的类型进行切割,例如十二宫格,是3行4列,切割后的图片是12张;三宫格是1行1列,切割后的图片是3张。
    切割完成后,将图片保存在数组中,图片数组就是UICollectionView的数据源。

    代码如下:

      //对大图进行切割,切割完成得到图片数组
    - (void)captureImage {
        //切割成正方形,宽高一样
        CGFloat  imgView_width = (self.imageView.frame.size.width / 3);
        CGFloat  imgView_height = (self.imageView.frame.size.width / 3);
    
        if (self.imgCount == 3) {
            // 把图片切成三宫格,就是竖着切3段
            for (int i = 0; i < 3; i++) {
                UIImage *theImage = [self captureView:self.imageView frame:CGRectMake(i*imgView_width, 0, imgView_width,imgView_height)];
                [self.imageArr addObject:theImage];
             }
            
        }else if (self.imgCount == 6){
            // 把图片切成六宫格,就是横着切2段,竖着切3段,2个for循环,对已知image进行切割
            for (int i = 0; i < 2; i++) {
                for (int j = 0; j<3; j++) {
                        UIImage *theImage = [self captureView:self.imageView frame:CGRectMake(j*imgView_width,i*imgView_height, imgView_width, imgView_height)];
                        [self.imageArr addObject:theImage];
                }
             }
            
        }else if (self.imgCount == 9){
           // 把图片切成九宫格,就是横着切3段,竖着切3段,2个for循环,对已知image进行切割
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j<3; j++) {
                        UIImage *theImage = [self captureView:self.imageView frame:CGRectMake(j*imgView_width, i*imgView_height, imgView_width, imgView_height)];
                        [self.imageArr addObject:theImage];
                 }
            }
            
        }else if (self.imgCount == 12){
            // 把图片切成十二宫格,就是横着切4段,竖着切3段,2个for循环,对已知image进行切割
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j<3; j++) {
                    NSLog(@"i===== %d j===== %d",i,j);
                    UIImage *theImage = [self captureView:self.imageView frame:CGRectMake(j*imgView_width, i*imgView_height, imgView_width, imgView_height)];
                    [self.imageArr addObject:theImage];
                }
            }
        }       
    }
    

    编辑页讲到了图片裁剪适应屏幕比例([UIScreen mainScreen].scale)的问题,这里也要考虑这个问题,那么我们的剪切位置frame.orgain.x与y都应该乘以scale的倍数。图片的剪切frame.size.width与height也应该乘以scale,而且在绘制好之后的压缩处理的时候也要除以[UIScreen mainScreen].scale,以达到选择区域的宽度和高度的图片范围)

    代码如下:

    //切割图片
    - (UIImage *)captureView:(UIView *)theView frame:(CGRect)fra {  
        //屏幕比例
        NSInteger multiple = [UIScreen mainScreen].scale;
        // 开启位图上下文
         UIGraphicsBeginImageContextWithOptions(theView.frame.size, NO, multiple);
       // 裁剪区域
        CGRect rect = CGRectMake(fra.origin.x * multiple, fra.origin.y * multiple, fra.size.width *multiple, fra.size.height * multiple);
        // 进行渲染
         CGContextRef ctx = UIGraphicsGetCurrentContext();
         [self.imageView.layer renderInContext:ctx];
    
        // 生成图片
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        //关闭上下文
        UIGraphicsEndImageContext();
        
        newImage = [UIImage imageWithCGImage:CGImageCreateWithImageInRect(self.imageView.image.CGImage, rect)];
        newImage = [self harfWithImage:newImage toSize:CGSizeMake(newImage.size.width /multiple, newImage.size.height / multiple)] ;
        return newImage;    
    }
    
    

    然后对照片进行“缩”处理,这个时候,获取的图片大小是我们想要的2倍大小。然后就需要进一步的“缩”1/2处理。
    再一次的缩处理,我们还是要缩放选择2.0.即目前的倍率(不然选择1倍或者不缩放处理,结果一样是模糊的图片)。然后将我们的图片绘制到一个宽度和高度都是目前一般的image就可以了。

    代码如下(将传入的size大小直接定为传入image的宽和高的一半就好了):

    -(UIImage *)harfWithImage:(UIImage *)image toSize:(CGSize)size{
        UIGraphicsBeginImageContextWithOptions(size, YES, [UIScreen mainScreen].scale);
        [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
        UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return resultImg;
    }
    
    

    3: 图片保存功能
    一次性保存多张图片,有时候会出现保存不全(例如保存12张图,实际只保存了6张)或保存的图片顺序错乱的问题,使用如下方法解决:

    
    //保存全部图片
    -(void)saveAllBtn:(UIButton *)sender{
       for (UIImage *image in self.sudokuSaveView.imageArr){
                [self loadImageFinished:image];
           }
    }
    
        // 存储图片到相册
    - (void)loadImageFinished:(UIImage *)image{
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            //写入图片到相册
            [PHAssetChangeRequest creationRequestForAssetFromImage:image];
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            NSLog(@"success = %d, error = %@", success, error);
            if(success){
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"保存成功,可以在这里做保存完成的操作");
                   
                });
            } else {
                NSLog(@"保存失败");
            }
        }];
    }
    

    结语:

    以上就是九宫格的核心功能实现

    如有问题请下方留言指正

    如有帮助请👍支持一下 😄

    相关文章

      网友评论

          本文标题:iOS 九宫格切图功能实现

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