<h3> ```diff - Warning - This has been attempted 3 times ``` </h3> ### Context Clients may want to set the corner radius of a UIView that they have overridden the layerClass on to use MDCShadowLayer. Currently if the shadow layer's corner radius changes those changes are not rendered (see Shadow Corner Radius example in MDCDragons). This has been attempted in [this PR](https://github.com/material-components/material-components-ios/pull/4921) and [this PR](https://github.com/material-components/material-components-ios/pull/5224) both had to be rolled back. This is a similar change to #4921 except this change does NOT mark `shadowPathIsInvalid` or call `setNeedsLayout`. This differs from #5224 in that it doesn't set the `shadowPath`'s for the sublayers or set `shadowPathIsInvalid`. ### The problem Corner radius changes aren't rendered when using MDCShadowLayer. ### The fix Set the corner radius on the layer and sublayers and update the mask for the sublayers. ### Additional notes A global presubmit has been run and succeeded. Internal CL to test: cl/216562497 ### Alternatives @andrewoverton Suggest ```objectivec -(void)setCornerRadius:(CGFloat)cornerRadius { [super setCornerRadius:cornerRadius]; [self layoutSublayers]; } ``` ### Videos | Before | After | | - | - | |||
Shadow layer
Shadow layer implements the Material Design specifications for elevation and shadows. By simulating the physical properties of paper, elevation and light source, shadows give visual depth to components. Shadow layer provides an elevation property which affects a shadow's depth and strength, automatically handling shadow diffusion based on the shadow's elevation.
Design & API Documentation
MDCShadowLayer
MDCShadowLayer provides a Core Animation CALayer that will render a shadow based on its
elevation property. UIViews can use this by overriding their layerClass method to
return MDCShadowLayer.
elevation sets the diffusion level of the shadow. The higher the shadow elevation, the more
diffused the shadow becomes. Elevation uses points as a unit to specify height. Common shadow
elevations are defined in MDCShadowElevations and range from 0 to 24 points.
The shadow diffusion effect diminishes as elevations exceed 24 points. The default value is 0 (no
shadow).
Set shadowMaskEnabled to ensure the interior, non-shadow portion of the layer is visible.
This is enabled by default and the internal portion of the layer is cut out.
MDCShadowMetrics
MDCShadowMetrics is a series of properties used to set MDCShadowLayer. MDCShadowLayer consists
of two distinct layers. The overlay of these two layers generates a single Material Design
shadow that adheres to defined height and light source principles.
Installation
Installation with CocoaPods
To add this component to your Xcode project using CocoaPods, add the following to your Podfile:
pod 'MaterialComponents/ShadowLayer'
Then, run the following command:
pod install
Usage
Importing
Before using shadow layer, you'll need to import it:
Swift
import MaterialComponents
Objective-C
#import "MaterialShadowLayer.h"
Example of a custom button based on UIButton with Material Design shadows:
Swift
class ShadowButton: UIButton {
override class var layerClass: AnyClass {
return MDCShadowLayer.self
}
}
Objective C
@interface ShadowButton : UIButton
@end
@implementation ShadowButton
+ (Class)layerClass {
return [MDCShadowLayer class];
}
@end
Add the custom button to view:
Swift
let button = ShadowButton(type: .system)
button.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
button.setTitle("Button", for: .normal)
let buttonLayer = button.layer as! MDCShadowLayer
buttonLayer.elevation = ShadowElevation(6)
addSubview(button)
Objective C
ShadowButton *button = [ShadowButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(100, 100, 200, 50);
[button setTitle: @"Button" forState:UIControlStateNormal];
[(MDCShadowLayer *)button.layer setElevation:6.f];
[self addSubview:button];
Creating a custom UIView with a shadow:
Swift
class ShadowedView: UIView {
override class var layerClass: AnyClass {
return MDCShadowLayer.self
}
var shadowLayer: MDCShadowLayer {
return self.layer as! MDCShadowLayer
}
var elevation: ShadowElevation {
get {
return self.shadowLayer.elevation
}
set {
self.shadowLayer.elevation = newValue
}
}
}
Objective C
@interface ShadowedView : UIView
@end
@implementation ShadowedView
+ (Class)layerClass {
return [MDCShadowLayer class];
}
- (MDCShadowLayer)shadowLayer {
return (MDCShadowLayer *)self.layer;
}
- (void)setElevation:(CGFloat)points {
[(MDCShadowLayer *)self.layer setElevation:points];
}
@end
To improve performance, consider rasterizing MDCShadowLayer when the view using the shadow is not animating or changing size.
Swift
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
Objective C
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
Disable rasterization before animating MDCShadowLayer.
