An implementation of the Material Design shape scheme is provided in the MDCShapeScheme
class. By default, an instance of this class is configured with the Material defaults. The following image shows an MDCButton themed with the default shape scheme values (bottom) and an MDCButton themed with custom shape scheme values (top).
Currently, 5 components support being themed with a shape scheme using a shape themer
extension, namely Cards, Buttons, FABs, Chips, and Bottom Sheet. You can learn more about which extensions are available for a given component by reading the component documentation.
A shape scheme consists of the following shape values:
Shape Category | Use |
---|---|
smallComponentShape | The shape defining small sized components. |
mediumComponentShape | The shape defining medium sized components. |
largeComponentShape | The shape defining large sized components. |
Each of the shape categories are of the class MDCShapeCategory
.
An MDCShapeCategory
holds properties that define a shape value. It consists of 4 corners of type MDCCornerTreatment
that represent each corner of the shape. It also has a convenience initializer to set all the 4 corners at once to the same value, creating a symmetrical shape.
Lastly, an MDCCornerTreatment
can be set by using any of the convenience initializers in MDCCornerTreatment+CornerTypeInitializer.h.
Below is a table showing how our shape categories are mapped to each component.
Small Components | Medium Components | Large Components |
---|---|---|
Button | Card | Bottom Sheet (modal) |
Chip | Dialog | Navigation Drawer (bottom) |
Extended FAB | ||
FAB | ||
Snackbar | ||
Textfield |
Add the following to your Podfile
:
pod 'MaterialComponents/schemes/Shape'
Then, run the following command:
pod install
To import the component:
import MaterialComponents.MaterialShapeScheme
#import "MaterialShapeScheme.h"
You'll typically want to create one default MDCShapeScheme
instance for your app where all of the shape properties are set to your desired brand or style.
let shapeScheme = MDCShapeScheme() // Small Component Shape shapeScheme.smallComponentShape = MDCShapeCategory(cornersWith: .cut, andSize: 4) // Medium Component Shape shapeScheme.mediumComponentShape = MDCShapeCategory(cornersWith: .rounded, andSize: 10) // Large Component Shape let largeShapeCategory = MDCShapeCategory() let rounded50PercentCorner = MDCCornerTreatment.corner(withRadius: 0.5, valueType: .percentage) let cut8PointsCorner = MDCCornerTreatment.corner(withCut: 8) largeShapeCategory?.topLeftCorner = rounded50PercentCorner largeShapeCategory?.topRightCorner = rounded50PercentCorner largeShapeCategory?.bottomLeftCorner = cut8PointsCorner largeShapeCategory?.bottomRightCorner = cut8PointsCorner shapeScheme.largeComponentShape = largeShapeCategory
MDCShapeScheme *shapeScheme = [[MDCShapeScheme alloc] init]; // Small Component Shape shapeScheme.smallComponentShape = [[MDCShapeCategory alloc] initCornersWithFamily:MDCShapeCornerFamilyCut andSize:4]; // Medium Component Shape shapeScheme.mediumComponentShape = [[MDCShapeCategory alloc] initCornersWithFamily:MDCShapeCornerFamilyRounded andSize:10]; // Large Component Shape MDCShapeCategory *largeShapeCategory = [[MDCShapeCategory alloc] init]; MDCCornerTreatment *rounded50PercentCorner = [MDCCornerTreatment cornerWithRadius:(CGFloat)0.5 valueType:MDCCornerTreatmentValueTypePercentage]; MDCCornerTreatment *cut8PointsCorner = [MDCCornerTreatment cornerWithCut:8]; largeShapeCategory.topLeftCorner = rounded50PercentCorner; largeShapeCategory.topRightCorner = rounded50PercentCorner; largeShapeCategory.bottomLeftCorner = cut8PointsCorner; largeShapeCategory.bottomRightCorner = cut8PointsCorner; shapeScheme.largeComponentShape = largeShapeCategory;
Choosing a shape value for your shape scheme or component has an effect on the component's content.
As an example, we may choose the smallComponentShape
category to have a cut corner treatment at a 50% value of its height. That will create a diamond-like shape, which in certain cases is likely to clip content. In other cases, such as with dynamic type, or a typography scheme with large fonts, even a less intrusive shape could potentially cut out content.
Therefore, it is recommended to be mindful of how a custom shape manipulates the component and if that shape makes sense for your specific case. One recommendation is to use the built-in UIView’s layoutMargins
. By setting it to a custom UIEdgeInset
you can get the desired outcome for your content when using a custom shape.