iOS 动态对UIImageView加载到的图片进行偏移裁剪处理

2024-04-18 1547阅读

关键点:图片偏移重绘、图片重绘时机处理

iOS 动态对UIImageView加载到的图片进行偏移裁剪处理
(图片来源网络,侵删)

1. 图片偏移重绘问题

  • 原因:UIImageView的现有填充模式已经不能满足应用需求,需自定义偏移量结合填充模式实现效果
  •  方法:按需求样式重绘,设置偏移量比例,偏移阈值,对图片进行裁剪。

    2. 重绘时机问题

    •  选择:UIImageView自带的setImage方法,这是获取图片和进行重绘渲染的关口,从这里处理最恰当
    •  方法:利用iOS底层方法,在运行时(runtime)进行方法交换,属性绑定等。

      3. 补充

      • 因为运行时编程代码复杂冗余多,可以考虑运用第三方库方法解决这个问题,此处选择德国软件工程师Philipp Rentzsch开发的一个开源库[JRSwizzle](https://github.com/rentzsch/jrswizzle)辅助完成。
      • 使用cocoapod集成JRSwizzle库

         

        核心代码:

        • 宏定义再次简化运行时代码

           

          #import 
          /* 方法交换宏*/
          #define MYSwizzle(prefix, SEL) \
              do {    \
                  NSError *error = nil; \
                  [[self class] jr_swizzleMethod: @selector(SEL) \
          withMethod: @selector(prefix##_##SEL)error:&error]; \
                  if (error) {NSLogError(@ "%@ swizzle %@ with %@ failed.", \
                                  NSStringFromClass(self), \
                                  NSStringFromSelector(@selector(SEL)), \
                                  NSStringFromSelector(@selector(prefix##_##SEL)));} \
              } while (0)
              
          /*添加属性宏*/
          #define MY_ASSOCIATE_OBJECT(_getter_, _setter_, _association_, _type_) \
                - (void)_setter_: (_type_)object { \
                      [self willChangeValueForKey: @#_getter_]; \
                      objc_setAssociatedObject(self, _cmd, object, OBJC_ASSOCIATION_##_association_); \
                      [self didChangeValueForKey: @#_getter_]; \
                  } \
                  -(_type_)_getter_ { \
                      return objc_getAssociatedObject(self, @selector(_setter_:)); \
                  }
          
          • 定义好红代码之后,写一个UIImageView的分类方法,记录加载原始图片imgOriginal,以及便宜设置类MYImaeViewOffset;
          • 首先定义偏移重绘配置类MYImaeViewOffset:
            /**
             *  用于判断和控制UIImageView设置图片时候的偏移量的数据类。
             *
             *  ratioOffsetX x轴方向的偏移量比例.
             *  ratioOffsetY y轴方向的偏移量比例.
             *
             *  ratioThreshold 进行偏移重绘的阈值. 实值为 imgv_w / imgv_h.
             *  如果设定ratioThreshold = 1.8, 而当前UIImageView.size = {100, 50}
             *  则实值为 2。此时超过偏移阈值,需对图片进行偏移裁剪重绘。
             *
             *  @note ignoreThreshold 注意如果此值为YES,则忽略阈值,需要重绘。
             */
            typedef NS_OPTIONS(NSUInteger, MYImageViewAlignmentMask) {
                MYImageViewAlignmentMaskCenter     = 1  0){
                        CGFloat ratioCR = cornerRadius * (outputImage.size.width / self.width);
                        UIGraphicsBeginImageContextWithOptions(outputImage.size, NO, outputImage.scale);
                        CGContextRef context = UIGraphicsGetCurrentContext();
                        CGRect imgRect = CGRectMake(0, 0, outputImage.size.width, outputImage.size.height);
                        
                        CGContextSaveGState(context);
                        [[UIBezierPath bezierPathWithRoundedRect:imgRect cornerRadius:ratioCR] addClip];
                        [outputImage drawInRect:imgRect];
                        CGContextRestoreGState(context);
                        UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
                        UIGraphicsEndImageContext();
                        outputImage =  roundedImage;
                    }
                    
                    if(self.offset.alignment != MYImageViewAlignmentMaskCenter){
                        CGFloat logicH = (outputImage.size.height * self.width)/outputImage.size.width;
                        CGFloat logicW = (outputImage.size.width * self.height)/outputImage.size.height;
                        CGFloat offsetH = (self.height - logicH);
                        CGFloat offsetV = (self.width - logicW);
                        BOOL needRedraw = NO;
                        if(offsetH > 0){ //横图(只有上下偏移)
                            offsetV = 0;
                            logicW = self.width;
                            if(self.offset.alignment == MYImageViewAlignmentMaskTop){
                                offsetH = 0;
                                needRedraw = YES;
                            }else if (self.offset.alignment == MYImageViewAlignmentMaskBottom){
                                needRedraw = YES;
                            }
                        }
                        if (offsetV > 0){ //竖图(只有左右偏移)
                            logicH = self.height;
                            offsetH = 0;
                            if(self.offset.alignment == MYImageViewAlignmentMaskLeft){
                                offsetV = 0;
                                needRedraw = YES;
                            }else if (self.offset.alignment == MYImageViewAlignmentMaskRight){
                                needRedraw = YES;
                            }
                        }
                        if(needRedraw){
                            UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
                            [outputImage drawInRect:CGRectMake(offsetV, offsetH, logicW, logicH)];
                            UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
                            UIGraphicsEndImageContext();
                            outputImage =  resizedImage;
                        }
                    }
                }
                return outputImage;
            }
            @end
            

            补充说明:

            说明

            1.  利用swizzle方法交换setImage 和layoutSubviews方法实现,它们将风别走向MY_setImage:和方法My_layoutSubviews从中获取到imgOriginal之后,再判断是否要进行重绘(needImageRedrawJudge),如果要进行重绘,重绘之后得到图片对象  destImg|imgOffset,这时候调用MY_setImage:方法,根据方法交换的逻辑,实际上就是调用了UIImageView的setImage:方法,从而实现拦截图片,并判断和重回图片在设置最终图片的效果。
            2.  至于图片重绘的具体逻辑,可根据具体需求进行灵活变换,此处重在说明如何判断需求和在拦截,以及拦截使用的方法,核心设计知识领域有:宏代码的编程简化、运行时方法、图片重绘
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]