iOS CoreAnimation (六) layer 属性:阴影,边框,圆角,masksToBounds

                   嗯,圆和椭圆还不错,但如果是带圆角的矩形呢?我们现在能做到那样了么?  ------Steve Jobs

本文介绍的属性相对于前几篇文章来说比较简单,开发也比较常用;核心内容是对阴影的理解。

1、masksToBounds 裁剪边界

下面代码,黄色视图超出了父视图蓝色视图的区域,可以复制代码运行查看效果。    

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
         
        let blueView = UIView(frame:CGRect(x:50, y: 200, width:350, height:300))
        blueView.backgroundColor = UIColor.lightGray
         
        let yellowView = UIView(frame:CGRect(x:-50, y:-50, width:200, height:200))
        yellowView.backgroundColor = UIColor.yellow
         
        blueView.addSubview(yellowView)
        view.addSubview(blueView)
    }
}

在以上代码加入 blueView.layer.masksToBounds = true,可以将超出边界部分裁剪掉。

// 相对应的 UIView 的属性:blueView.clipsToBoundstrue

2、cornerRadius 圆角

加入以下代码:

        yellowView.layer.cornerRadius15

        blueView.layer.cornerRadius15

        // cornerRadius:角落半径,圆角的半径是多少 pt

 

更改5个字母,再运行一遍:  yellowView 从 UIVew 换成 UILabel,其他都不变。

发现 label 右下角的圆角没了!咋回事?

深入解释 cornerRadius :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 true causes the content to be clipped to the rounded corners.

大致意思是,圆角对于 layer 的 contents 属性(之前介绍过,一般是 CGImage)不起作用,如果想让 contents 也圆角,就设置 masksToBounds 为 true。

因此我们可以猜测,UILabel 内部可能是绘制文字作为寄宿图显示的,这些并不重要,重要的是知道:

yellowView.layer.masksToBoundstrue 就可以让 label 有圆角了!

那如何知道一个视图是否自己绘制了寄宿图呢?目前应该只能靠经验... UILabel、UIImageView 是最常见的使用寄宿图的系统控件...

 

对了,如果想让四个角中的某几个是圆角,其他是直角呢?这就需要用到图层蒙板(下一篇提到) 或者 CAShapeLayer(后面“专用图层”提到)。  

3、borderColor、borderWidth 边框

再次运行,加上:

        blueView.layer.borderColor = UIColor.red.cgColor

        blueView.layer.borderWidth10

图层绘制了边线。这条边线(也被称作stroke)沿着图层的 bounds 绘制,同时也包含圆角。

注意:边框是绘制在图层边界内侧的,而且在所有子内容之前,也在子图层之前 !

为了验证在子图层之前,我们把裁剪关掉,可以尝试用一下这个属性,同样是裁剪开关:

blueView.clipsToBoundsfalse 

运行后就可以看到效果了!

 

4、阴影

介绍 CALayer 的几个属性。

shadowOpacity: 可以当作阴影的初始透明度,在 0.0 (默认,不可见的阴影) 和1.0 (完全不透明的阴影) 之间的浮点数。只要设置一个大于 0 的值,就会显示一个有轻微模糊的黑(默认)色阴影在图层上。若要改动阴影的表现,可以使用 CALayer 的另外几个属性: shadowColor,shadowOffset,shadowRadius,shadowPath。

第一个是阴影颜色不需要多解释;

第二个是阴影偏移量:一个 CGSize 值,宽度控制阴影横向偏移,高度控制纵向偏移。 默认值(0, -3),即阴影相对于 Y 轴有 3 个点的向上位移。大家注意到 macOS 里的阴影都是在窗口左右下方,上方没有;在iOS里,因为之前说过的 两个系统排版的坐标翻转问题,使 iOS 把阴影搞到反向上方了。如果需要显示在下方的阴影,要手动设置正数。

第三个是阴影模糊度:值是 0 的时候,阴影就像一条边界线(只是像一条线,实际是实心的一大块)。当值越来越大的时候,边界线看上去就会越来越模糊(自然)。苹果自家的应用设计更偏向于自然的阴影,所以一般使用非零值(默认 3 pt)。单词 radius 是半径,也可以视为边界线的宽度,在这个距离内,背景色由 shadowColor(opacity 是初始透明度)渐变到透明,就成了阴影。

第四个是完全自定义的阴影绘制形状路径,CGPath,下篇文章会具体介绍它。

 

前面提到图层边框是沿着图层边界绘制的,但是阴影是沿着 “内容” 的外形绘制的(如果有的话)(如果没有指定 shadowPath)!!!那么阴影的最终形状是怎么计算的呢?

系统会考虑:1 寄宿图的轮廓;2 背景颜色;3 递归计算子视图的阴影形状,结合三者形成最终 “内容” 的形状,并绘制阴影;4 特殊情况如 CAShapeLayer 的 path 等

这也是为什么直接给 UILabel 设置阴影,阴影会出现在文字上,而设置背景色之后,阴影出现在边框上。

 

此外,业务上经常同时出现阴影和圆角裁剪,但开启了 masksToBounds 属性,阴影都被剪掉了。常用的办法是 用两个视图,一个画阴影的父视图,一个显示圆角的子视图。

需要注意刚才提到的阴影计算方式,如果希望阴影出现在视图边界,恰好视图没有背景色或寄宿图,那么必须设置 shadowPath,或简单一点,直接设置子视图的背景色,作为系统计算出的阴影路径。

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 真正的内容
        let v: UIView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 100)))
        v.layer.cornerRadius = 10
        v.layer.masksToBounds = true
        v.backgroundColor = .red
        
        // 呈现阴影
        let out = UIView(frame: CGRect(x: 100, y: 200, width: 100, height: 100))
        out.layer.shadowOpacity = 1
        out.layer.shadowRadius = 5
        out.layer.shadowOffset = CGSize(width: 0, height: 5)
      
        view.addSubview(out)
        out.addSubview(v)
    }
}
 

运行可以看到目标实现了


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值