前段时间项目中有个特殊的需求,折腾了好久,觉得有必要总结一下。我自己写了一个日历控件,产品要求选中的日期要用圆形图片显示出来,如图所示
方案一
刚开始以为只要用layer.cornerRadius就可以了,但是真正实现起来的时候才发现不是那么简单。因为我的日历控件宽度设置为屏幕宽度,那么问题就来了,日历一行只能显示七天,所以不同屏幕宽度下每个单元view的宽度就不固定了,而且还不是正方形,用layer.cornerRadius的话就会出来一个椭圆形的选中效果,第一种方案就放弃了。
方案二
第二种方案我是想着放一个遮罩,既然itemView不一定是正方形,那我们想办法让它只显示出来正方形的区域就好了。于是用UIBezierPath+CAShapeLayer画出一个圆形的遮罩添加在每个单元view的layer上,设置为itemView.layer.mask为画出的圆形CAShapeLayer,运行一看满足了要求。但出现一个新的问题就是,每次进到这个界面的时候屏幕都会卡顿,能看出明显的抖动,这肯定是不能忍的。只能查找原因优化~
大概原因是设置layer的mask属性会触发离屏渲染,大大的消耗了性能,所以卡顿。其中有一种优化方案就是开启GPU的栅格化,然后把需要渲染的画面缓存起来,等下次进来的时候可以直接加载
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = self.layer.contentsScale;
试了一下果然不卡了,但是新的问题又出现了,就是日历上的数字都变得模糊了。我推断出大概是以下原因,当shouldRasterize设成true时,layer被渲染成一个bitmap,并缓存起来,等下次使用时不会再重新去渲染了。实现圆角本身就是在做颜色混合(blending),如果每次页面出来时都blending,消耗太大,这时shouldRasterize = yes,下次就只是简单的从渲染引擎的cache里读取那张bitmap,节约系统资源。我这边要渲染的是文字,估计在layer被渲染成bitmap的过程或者读取bitmap的时候产生了一些误差,所以导致文字看上去有些模糊。
接着优化~
方案三
我在itemView上边覆盖一个中间为圆形透明区域的图片,正方形的图片中心点与itemView的中心点重合。这样解决了卡顿问题,而且也很清晰,但是新的问题出现了,就是我选中的时候要改变itemView的颜色,这时候如果itemView宽度大于高度的时候,就会出现左右两边的颜色没有被覆盖的情况,没办法……
接着优化~
方案四
反向选取区域,既然处理不了中间的圆形区域,那我能不能把周围的处理一下嘞~最后终于是功夫不负有心人,就是这个方法bezierPathByReversingPath,用代码说话吧
- (void)drawRect:(CGRect)rect{
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat radius = MIN(self.width, self.height)*0.5-2;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
UIBezierPath *clipPath = [[UIBezierPath bezierPathWithRoundedRect:CGRectMake((self.width-radius*2)*0.5, (self.height-radius*2)*0.5, radius*2, radius*2) cornerRadius:radius] bezierPathByReversingPath];
[path appendPath:clipPath];
CGContextAddPath(context, path.CGPath);
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillPath(context);
}
我自定义了一个继承自UILabel的GRCalendarTileLabel控件,在drawRect方法中把中间圆形区域以外的区域设置为了白色,这样一来不管你外边是什么形状,我只留出中间一块儿圆形区域,这里记得调用[super drawRect:rect]方法,不然给Label设置text的时候是不会显示的。如下图所示
这样一来,问题就算完美解决了。虽然过程中费了不少周折,但是问题解决的时候还是很有成就感滴,特此记录总结一下,希望能给有同样需求的小伙伴一点帮助,欢迎大家积极提出指导意见~~~