渐变色踩的坑

这些坑踩的好疼

个人的域名和blog搭建好了有一段时间,但是一直没有抽时间来写自己的blog。所以就抽了一点时间来记录一下,最近项目中遇到的一些坑。言归正传,最近的项目中,UI的设计图里出了一个渐变色的按钮,而且按钮点击的时候还需要一个透明度为0.3的黑色遮盖在渐变色上。然后,坑就开始了。

第一个大坑(hitTest:withEvent:)

我实现的大体思路是把渐变色绘制成image设置成按钮的背景图,然后,在button上添加一个view,没点击时,设置为透明色,点击时设置为alpha为0.3的黑色。因为点击button的事件会被view给拦截掉。所以,我就在自己创建的button里重写了如下方法:

#pragma mark - 转换点击
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 1.判断当前控件能否接收事件
    if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
    // 2.判断点在不在coverView上
    if ([self.coverView pointInside:point withEvent:event]) return self;
    // 3. 判断点在不在当前控件
    if ([self pointInside:point withEvent:event] == NO) return nil;
}
  1. 第一个判断是如果当前的视图不能交互,被隐藏,或者alpha值<0.01的话,此次Touch操作初始点所在的视图就返回为nil。
  2. 第二个判断是调用 pointInside: withEvent:方法,判断当前touch的点在不在添加到button上的view上,如果在上面,就返回button,让button来响应点击
  3. 第三个判断如果当前的点击不在覆盖的view上就返回nil.

刚开始的时候,并没有测试出问题,然后一次偶然的点击触发了一系列的问题。刚开始只是在一个包含我的渐变色按钮的页面点击出现了奔溃,我们并没有往我的按钮那里去想,最后在其他界面点击也会出现奔溃,控制台打印出来的奔溃信息是[UIWindow dealloced];
内心很奔溃,我们定位了很久,比较不同的版本,修改按钮为普通按钮,最后终于定位到了上述方法上。
触发这个问题的方式就是,触碰按钮的边缘,然后就会100%的复现这个问题,分析原因应该就是我的最后一个判断,处理得太唐突,当点不在button或者coverView上的时候,直接返回了nil。最后利用

CGPoint subPoint = [subview convertPoint:point fromView:self];
UIView *result = [subview hitTest:subPoint withEvent:event];

处理了一下,就好了。但是最后由于怕有疏忽。所以放弃了这种方式处理。然后就有了第二种坑。

第二个坑(CGColorSpaceRelease(colorSpace))

在一个坑中,我最后放弃了在button上添加遮盖的处理方式,而是在点击button的时候,先是将渐变色绘制成图片,再将遮盖色绘制成图片,最后将两张图片绘制成一张图片,设置为button的背景色。核心代码如下:

#pragma mark --渐变色
+ (UIImage *)setGradualChangeColor:(NSArray *)colors
                        startPoint:(CGPoint)startPoint
                          endPoint:(CGPoint)endPoint
                             frame:(CGRect)frame {
    NSMutableArray *cgColors = [NSMutableArray array];
    for(UIColor *c in colors) {
        [cgColors addObject:(id)c.CGColor];
    }

    UIGraphicsBeginImageContextWithOptions(frame.size, YES, 1);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors lastObject] CGColor]);
    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)cgColors, NULL);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    CGGradientRelease(gradient);
    CGContextRestoreGState(context);
//    CGColorSpaceRelease(colorSpace);
    UIGraphicsEndImageContext();
    return image;
}

#pragma mark - 设置带有阴影的渐变色
- (UIImage *)createGraduallyCoverImage:(UIImage *)graduallyImage
                            coverImage:(UIImage *)coverImage {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 2);

    [graduallyImage drawInRect:CGRectMake(0, 0, self.width, self.height)];
    [coverImage drawInRect:CGRectMake(0, 0, self.width, self.height)];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

然后在有渐变色按钮的地方,有一定的概率触发崩溃,当时为了定位这个问题,就多点几次按钮,然后打断点,打开了僵尸对象调试,发现打印的奔溃信息是:
Assertion failed: (!state->is_singleton), function color_space_state_dealloc, file ColorSpaces/CGColorSpace.c, line 127.
然后就开始在网上找相关的问题,然后在一篇blog中找到了症结所在。具体的原因就是,第一个方法中我注释掉的那行代码。在苹果的api中指出,如果你需要维持这个实例,retain 它,如果没有 retain ,不要 release 它。所以由于我将其release掉了,就会有一定的几率触发奔溃。处理方式,就是注释掉CGColorSpaceRelease(colorSpace);这行代码,就OK了。

总结

由于在以前的开发中很少手动处理hitTest:withEvent:,以及接触绘图这一块,所以在开发中出现了上述的问题,还好在互联网发达的今天,能够快速的在网上找到解决方案。对于不太懂hitTest:withEvent:的,可以看看这一篇文章,作者写的很到位。当时还看了一篇讲解convertPoint: fromView:convertPoint: toView:几个方法的作用的文章。也可以在网上找找其他的看看。
最后,谢谢这些文章的作者,正是有了他们的经验,才为我们这些后来的开发者,提供了宝贵的经验。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值