Cards contain content and actions about a single subject.
In order to use Material cards, first add the Cards
subspec to your Podfile
:
pod MaterialComponents/Cards
Then, run the installer:
pod install
After that, import the relevant target or file.
import MaterialComponents.MaterialCards
#import "MaterialCards.h"
On iOS, the Cards component offers two implementations to choose from, MDCCard
and MDCCardCollectionCell
.
MDCCard
subclasses UIControl
. Subclassing MDCCard
allows you to create cards that match the Material spec.
MDCCard
uses UIControlState
to represent state. Its styling changes depending on whether its state is .normal
or .highlighted
.
MDCCard
allows the following properties to be customized:
- The border width for a specific state
- The border color for a specific state
- The shadow elevation for a specific state
- The shadow color for a specific state
- The corner radius for the card
MDCCardCollectionCell
subclasses UICollectionViewCell
. Subclassing MDCCardCollectionCell
allows you to have Material cards as cells in your UICollectionView
.
MDCCardCollectionCell
has its own notion of state, MDCCardCellState
, which is tied to the UICollectionViewCell
highlighted
and selected
properties.
In addition to those offered by MDCCard
, MDCCardCollectionCell
offers the following customization options:
- Changing the image that appears in the Selected state.
- Changing the image tint color that appears in the Selected state.
Accessibility best practices depend on whether you are using an MDCCard
or an MDCCardCollectionCell
.
The nested elements in an MDCCard
are available to assistive technologies without additional
customization. However, additional setup may be needed to accommodate the following scenarios:
Images may have additional context beyond text that is already presented on the card. For example, news article images can benefit from an
accessibilityLabel
describing their content.
articleImageView.isAccessibilityElement = true
articleImageView.accessibilityLabel = "Event or scene description"
articleImageView.isAccessibilityElement = YES;
articleImageView.accessibilityLabel = @"Event or scene description";
Star or rating images should have accessibilityLabel
property values describing their purpose and accessibilityValue
property values describing their rating value.
ratingView.isAccessibilityElement = true
ratingView.accessibilityLabel = "Average customer rating, out of " +
"\(MDCProductRating.maximumValue) stars"
ratingView.accessibilityValue = (String)product.averageRating
ratingView.isAccessibilityElement = YES;
ratingView.accessibilityLabel = [NSString stringWithFormat:@"Average customer" +
" rating, out of %d stars", MDCProductRating.maximumValue];
ratingView.accessibilityValue = @(product.averageRating).stringValue;
Primary content or actions that appear lower on the screen will be read last by assistive
technologies, sometimes after longer or non-primary content. To change the order, or group
elements together, you can make the card an accessibility container by adopting the
UIAccessibilityContainer
protocol. Grouping and order is controlled by creating as many
UIAccessibilityElement
elements as needed, and returning them in the desired order.
Since assistive technologies visit all cards in a collection in a sequential order, it is often
easier to distinguish between elements that belong to different cards by aggregating all the
card's information so the card is read as a single sentence. This can be done by setting an appropriate
accessibilityLabel
for the card. Additionally, set the card's
isAccessibilityElement
to true. Cards are a container element and setting isAccessibiltyElement
for a container
turns off individually selecting its subelements.
card.isAccessibilityElement = true
card.accessibilityLabel = "Location \(userLocation.name) is popular with users " +
"who enjoy \(userLocation.popularActivityMatchingUserProfile(userProfile))"
card.isAccessibilityElement = YES;
card.accessibilityLabel = [NSString
stringWithFormat:@"Location %@ is popular with users who enjoy %@",
userLocation.name,
userLocation.popularActivityMatchingUserProfile(userProfile)];
While iOS has two different implementations for Cards, there is really only one type of card from the design perspective. The example above could be built using either an MDCCard
or an MDCCardCollectionCell
. Here is an example class that does it with MDCCard
.
MDCCard
can be used like a regular UIView
. This is an example of a regular card:
let card = MDCCard(frame: CGRect(x: 30, y: 100, width: 150, height: 150))
card.applyTheme(withScheme: containerScheme)
view.addSubview(card)
MDCCard *card = [[MDCCard alloc] initWithFrame:CGRectMake(30, 100, 150, 150)];
[card applyThemeWithScheme:containerScheme];
[view addSubview:card];
MDCCardCollectionCell
GitHub source
MDCCardCollectionCell
can be used like a regular UICollectionViewCell
. This is an example of MDCCardCollectionCell
s in a collection:
collectionView.register(MDCCardCollectionCell.self, forCellWithReuseIdentifier: "Cell")
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
for: indexPath) as! MDCCardCollectionCell
// If you wanted to have the card show the selected state when tapped
// then you need to turn isSelectable to true, otherwise the default is false.
cell.isSelectable = true
cell.cornerRadius = 8
return cell
}
[self.collectionView registerClass:[MDCCardCollectionCell class]
forCellWithReuseIdentifier:@"Cell"];
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MDCCardCollectionCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:@"Cell"
forIndexPath:indexPath];
// If you wanted to have the card show the selected state when tapped
// then you need to turn selectable to true, otherwise the default is false.
[cell setSelectable:YES];
[cell setCornerRadius:8];
return cell;
}
A card has a container and an optional thumbnail, header text, secondary text, media, supporting text, buttons and icons.
- Container
- Thumbnail
- Header text
- Secondary text
- Media
- Supporting text
- Buttons
- Icons
- Checked icon (not shown)
Note: All the optional elements of a card's content are implemented through the use of other views/components.
Attribute | Related method(s) | Default value | |
---|---|---|---|
Color | backgroundColor |
-setBackgroundColor: backgroundColor: |
Surface color |
Foreground color | N/A | N/A | N/A |
Stroke color | layer.borderColor |
-setBorderColor:forState: -borderColorForState: |
On surface color at 37% opacity |
Stroke width | layer.borderWidth |
-setBorderWidth:forState: -borderWidthForState: |
1 |
Shape | shapeGenerator |
-setShapeGenerator: -shapeGenerator |
MDCRectangleShapeGenerator |
Elevation | N/A | -setShadowElevation:forState: -shadowElevationForState: |
1 |
Ripple color | rippleView.rippleColor |
N/A | nil |
Attribute | Related method(s) | Default value | |
---|---|---|---|
Color | backgroundColor |
-setBackgroundColor: backgroundColor: |
Surface color |
Foreground color | N/A | N/A | N/A |
Stroke color | layer.borderColor |
-setBorderColor:forState: -borderColorForState: |
On surface color at 37% opacity |
Stroke width | layer.borderWidth |
-setBorderWidth:forState: -borderWidthForState: |
1 |
Shape | shapeGenerator |
-setShapeGenerator: -shapeGenerator |
MDCRectangleShapeGenerator |
Elevation | N/A | -setShadowElevation:forState: -shadowElevationForState: |
1 |
Ripple color | rippleView.rippleColor |
N/A | nil |
Cards supports Material Theming using a Container Scheme. MDCCard
and MDCCardCollectionCell
have both default and outlined theming methods. Learn more about theming extensions here. Below is a screenshot of an MDCCard
with the Material Design Shrine theme:
To make use of Cards theming install the Cards theming extensions with Cocoapods. First, add the following line to your Podfile
:
pod MaterialComponents/Cards+Theming
Then run the installer:
pod install
Next, import the Cards theming target, and call the correct theming method.
import MaterialComponents.MaterialCards
import MaterialComponents.MaterialCards_Theming
...
// Create a card
let card = MDCCard()
// Create or use your app's Container Scheme
let containerScheme = MDCContainerScheme()
// Theme the card with either default theme
card.applyTheme(withScheme: containerScheme)
// Or outlined theme
card.applyOutlinedTheme(withScheme: containerScheme)
#import "MaterialCards.h"
#import "MaterialCards+Theming.h"
...
// Create a card
MDCCard *card = [[MDCCard alloc] init];
// Create or use your app's Container Scheme
MDCContainerScheme *containerScheme = [[MDCContainerScheme alloc] init];
// Theme the card with either default theme
[self.card applyThemeWithScheme:containerScheme];
// Or outlined theme
[self.card applyOutlinedThemeWithScheme:containerScheme];