给属性一个大于默认值(也就是0)的值,阴影就可以显示在任意图层之下。shadowOpacity是一个必须在0.0(不可见)和1.0(完全不透明)之间的浮点数。如果设置为1.0,将会显示一个有轻微模糊的黑色阴影稍微在图层之上。若要改动阴影的表现,你可以使用CALayer的另外三个属性:shadowColorshadowOffsetshadowRadius

        显而易见,shadowColor属性控制着阴影的颜色,和borderColorbackgroundColor一样,它的类型也是CGColorRef。阴影默认是黑色,大多数时候你需要的阴影也是黑色的(其他颜色的阴影看起来是不是有一点点奇怪。。)。

        shadowOffset属性控制着阴影的方向和距离。它是一个CGSize的值,宽度控制这阴影横向的位移,高度控制着纵向的位移。shadowOffset的默认值是 {0, -3},意即阴影相对于Y轴有3个点的向上位移。

        为什么要默认向上的阴影呢?尽管Core Animation是从图层套装演变而来(可以认为是为iOS创建的私有动画框架),但是呢,它却是在Mac OS上面世的,前面有提到,二者的Y轴是颠倒的。这就导致了默认的3个点位移的阴影是向上的。在Mac上,shadowOffset的默认值是阴影向下的,这样你就能理解为什么iOS上的阴影方向是向上的了(如图4.5).

    图4.5 在iOS(左)和Mac OS(右)上shadowOffset的表现。

        苹果更倾向于用户界面的阴影应该是垂直向下的,所以在iOS把阴影宽度设为0,然后高度设为一个正值不失为一个做法。

        shadowRadius属性控制着阴影的模糊度,当它的值是0的时候,阴影就和视图一样有一个非常确定的边界线。当值越来越大的时候,边界线看上去就会越来越模糊和自然。苹果自家的应用设计更偏向于自然的阴影,所以一个非零值再合适不过了。

        通常来讲,如果你想让视图或控件非常醒目独立于背景之外(比如弹出框遮罩层),你就应该给shadowRadius设置一个稍大的值。阴影越模糊,图层的深度看上去就会更明显(如图4.6).

    图4.6

    图4.7 阴影是根据寄宿图的轮廓来确定的

    &nbps;   当阴影和裁剪扯上关系的时候就有一个头疼的限制:阴影通常就是在Layer的边界之外,如果你开启了masksToBounds属性,所有从图层中突出来的内容都会被才剪掉。如果我们在我们之前的边框示例项目中增加图层的阴影属性时,你就会发现问题所在(见图4.8).

    图4.8

    图4.8 maskToBounds属性裁剪掉了阴影和内容

    &nbps;   从技术角度来说,这个结果是可以是可以理解的,但确实又不是我们想要的效果。如果你想沿着内容裁切,你需要用到两个图层:一个只画阴影的空的外图层,和一个用裁剪内容的内图层。

    &nbps;   如果我们把之前项目的右边用单独的视图把裁剪的视图包起来,我们就可以解决这个问题(如图4.9).

    图4.9 右边,用额外的阴影转换视图包裹被裁剪的视图

    &nbps;   我们只把阴影用在最外层的视图上,内层视图进行裁剪。清单4.3是代码实现,图4.10是运行结果。

    图4.10

    图4.10 右边视图,不受裁切阴影的阴影视图。

    shadowPath属性

        我们已经知道图层阴影并不总是方的,而是从图层内容的形状继承而来。这看上去不错,但是实时计算阴影也是一个非常消耗资源的,尤其是图层有多个子图层,每个图层还有一个有透明效果的寄宿图的时候。

        如果你事先知道你的阴影形状会是什么样子的,你可以通过指定一个shadowPath来提高性能。shadowPath是一个CGPathRef类型(一个指向CGPath的指针)。CGPath是一个Core Graphics对象,用来指定任意的一个矢量图形。我们可以通过这个属性单独于图层形状之外指定阴影的形状。

    图4.11 展示了同一寄宿图的不同阴影设定。如你所见,我们使用的图形很简单,但是它的阴影可以是你想要的任何形状。清单4.4是代码实现。

    图4.11 用shadowPath指定任意阴影形状

    清单4.4 创建简单的阴影形状

    1. @interface ViewController ()
    2. @property (nonatomic, weak) IBOutlet UIView *layerView1;
    3. @property (nonatomic, weak) IBOutlet UIView *layerView2;
    4. @end
    5. @implementation ViewController
    6. - (void)viewDidLoad
    7. {
    8. [super viewDidLoad];
    9. //enable layer shadows
    10. self.layerView1.layer.shadowOpacity = 0.5f;
    11. self.layerView2.layer.shadowOpacity = 0.5f;
    12. //create a square shadow
    13. CGPathAddRect(squarePath, NULL, self.layerView1.bounds);
    14. self.layerView1.layer.shadowPath = squarePath; CGPathRelease(squarePath);
    15. //create a circular shadow
    16. CGMutablePathRef circlePath = CGPathCreateMutable();
    17. CGPathAddEllipseInRect(circlePath, NULL, self.layerView2.bounds);
    18. self.layerView2.layer.shadowPath = circlePath; CGPathRelease(circlePath);
    19. }
    20. @end

        如果是一个矩形或者是圆,用CGPath会相当简单明了。但是如果是更加复杂一点的图形,UIBezierPath类会更合适,它是一个由UIKit提供的在CGPath基础上的Objective-C包装类。

    图4.6 大一些的阴影位移和角半径会增加图层的深度即视感