最近做到一个圆角加阴影的需求,忽然有一阵迷茫,相信很多小伙伴也跟我一样,第一时间想到的问题就是:我切圆角的时候直接就把阴影一起切掉了,还怎么加阴影。想到这里我就不由自主的想要问一下各位简书大佬。然后得到的答案也是五花八门,有在底层加个view的,有在底层加个layer的。但是这些都不是我心中的最优解,原因有二:
- 第一,单个控件加特效为什么会冲突,为什么需要用两个控件来实现一个控件上的特效。
- 第二,如果我上面的button半透明且需要移动,你需要将这个控件封装,如果你项目里每个控件都有圆角+阴影的特效,那么你的每个button都占用两份内存空间。个人觉着这极不合理。
那么问题出现在哪呢?其实刚才已经问过了,问题就在于圆角和阴影为什么会打架。
那么圆角和阴影他们有关系吗?有那么一丢丢,他们都是通过layer层实现的特效。layer层主要包括三种特效,还有一种是边框。这三种效果在控件效果中相当常见。
那么我们分别来看一下圆角和阴影的实现方法:
阴影的实现方法很直接,设置阴影的四项属性:颜色、偏移、透明度、半径。
button.layer.shadowColor = [UIColor blackColor].CGColor;
button.layer.shadowOpacity = 1;
button.layer.shadowRadius = 10.0;
button.layer.shadowOffset = CGSizeMake(5, 5);
这看起来没有问题,而且在我们的第一认识里面也认为是圆角切掉了阴影,那么我们再看圆角的实现方法:
button.layer.cornerRadius = 10;
button.layer.masksToBounds = YES;
我们一般习惯上这么写,这看起来似乎也没有问题,但是写到这里聪明的小伙伴们一定想到了什么:masksToBounds
,但是细心的我还是去翻了一下文档,然后理所当然的发现了点什么,可以让我的表达更具说服力。
mask
The layer’s alpha channel determines how much of the layer’s content and background shows through. Fully or partially opaque pixels allow the underlying content to show through, but fully transparent pixels block that content.
masksToBounds
When the value of this property is YES, Core Animation creates an implicit clipping mask that matches the bounds of the layer and includes any corner radius effects. If a value for the mask property is also specified, the two masks are multiplied to get the final mask value.
也就是说,mask层并没有对layer本身的圆角属性进行修改,而是创建了一个剪切蒙版,默认跟layer是一样的大小,而且包含圆角效果,蒙版之外的部分将不会显示。那么在创建蒙版之前,layer的圆角是否已经可以显示了呢?那么我们就要来看 cornerRadius
了:
Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to YES causes the content to be clipped to the rounded corners.
结合简单的实践,我们可以确认文档里传达的信息,cornerRadius切出的圆角效果是可以直接显示的,但是 图片 除外。
如果你只是一个拥有背景色的button,用cornerRadius设置圆角,然后添加阴影显示,不执行masksToBounds = YES 当然是可以实现的,但是,现实真的会如此吗?不要太天真了。你连圆角和阴影这样的效果都加了,让你区分一下 normal
、highlight
、disable
状态下不同的背景颜色不过分吧。那么你会怎么实现呢?或者说,项目中原来是怎么实现的呢?
你会发现,UIButton的backgrouncolor是不区分state设置的,如果你想从这个属性进行区分,那么你就要监听这个button的状态,但是对不起,button的state属性也是不完全开放独立读取的,我们只能获取到disable的状态。也许你会直接使用更简单的backgroundImage属性,这个可以直接区分状态设置的属性,将颜色转成图片设置,来完成这个不同状态下背景色不同的效果,那么恭喜你,不设置masksToBounds的情况下,圆角就切不出来了,因为背景是图片。
现在问题已经相当明朗,如果你的产品不要求你切换不同状态时的按钮颜色,那么你完全可以放心的不去设置 masksToBounds ,在他们改变主意之前。
如果你既想要圆角加阴影的效果,又想要炫酷的按钮背景和多元的按钮交互,只有一个办法:搞图。
- 如果你的背景不只有颜色,还有更加炫酷的花纹,那么一定要让UI妹子把圆角切出来,而且各种颜色要全。
- 如果你的按钮只有背景色,而你们又是用代码将颜色转化为图片,那么怎么办呢?
不要着急,给你:
- (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size andcornerRadius:(CGFloat)radius {
if (!color || size.width <= 0 || size.height <= 0) return nil;
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextMoveToPoint(context, size.width, size.height - radius); // 开始坐标右边开始
CGContextAddArcToPoint(context, size.width, size.height, size.width - radius, size.height, radius); // 右下角角度
CGContextAddArcToPoint(context, 0, size.height, 0, size.height - radius, radius); // 左下角角度
CGContextAddArcToPoint(context, 0, 0, radius, 0, radius); // 左上角
CGContextAddArcToPoint(context, size.width, 0, size.width, radius, radius); // 右上角
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
画一个带圆角的嘛!
写的有点糙,希望各位大佬多多包涵,告辞,留步。
网友评论