diff --git a/components/List/README.md b/components/List/README.md index 3265351e8..858444bc4 100644 --- a/components/List/README.md +++ b/components/List/README.md @@ -251,32 +251,66 @@ The example files can be found here List Cell Example -Our example consists of a custom `UICollectionViewController`: examples/CollectionListCellExampleTypicalUse.m -and also of a custom `UICollectionViewCell`: examples/supplemental/CollectionViewListCell.m. +Our example consists of a custom `UICollectionViewController`: examples/CollectionListCellExampleTypicalUse.m +and also of a custom `UICollectionViewCell`: examples/supplemental/CollectionViewListCell.m. -The main focus will be on the custom cell as that's where all the logic goes in, whereas the collection view and its controller are using mostly boilerplate code of setting up a simple example and collection view. +The main focus will be on the custom cell as that's where all the logic goes +in, whereas the collection view and its controller are using mostly +boilerplate code of setting up a simple example and collection view. ### Layout -For our example we will have a layout consisting of a left aligned `UIImageView`, a title text `UILabel` and a details text `UILabel`. The title text will have a max of 1 line whereas the details text can be up to 3 lines. It is important to note that neither the image nor the labels need to be set. To see more of the spec guidelines for Lists please see here: https://material.io/go/design-lists -To create our layout we used auto layout constraints that are all set up in the `(void)setupConstraints` method in our custom cell. It is important to make sure we set `translatesAutoresizingMaskIntoConstraints` to `NO` for all the views we are applying constraints on. +For our example we will have a layout consisting of a left aligned +`UIImageView`, a title text `UILabel` and a details text `UILabel`. The title +text will have a max of 1 line whereas the details text can be up to 3 lines. +It is important to note that neither the image nor the labels need to be set. +To see more of the spec guidelines for Lists please see here: https://material.io/go/design-lists + +To create our layout we used auto layout constraints that are all set up in +the `(void)setupConstraints` method in our custom cell. It is important to +make sure we set `translatesAutoresizingMaskIntoConstraints` to `NO` for all +the views we are applying constraints on. ### Ink Ripple -Interactable Material components and specifically List Cells have an ink ripple when tapped on. To add ink to your cells there are a few steps you need to take: + +Interactable Material components and specifically List Cells have an ink +ripple when tapped on. To add ink to your cells there are a few steps you need +to take: 1. Add an `MDCInkView` property to your custom cell. 2. Initialize `MDCInkView` on init and add it as a subview: + +#### Objective-C + ```objc _inkView = [[MDCInkView alloc] initWithFrame:self.bounds]; _inkView.usesLegacyInkRipple = NO; [self addSubview:_inkView]; ``` -3. Initialize a `CGPoint` property in your cell (`CGPoint _lastTouch;`) to indicate where the last tap was in the cell. +#### Swift -4. Override the `UIResponder`'s `touchesBegan` method in your cell to identify and save where the touches were so we can then start the ripple animation from that point: +```swift +let inkView = MDCInkView(frame: bounds) +inkView.usesLegacyInkRipple = false +addSubview(inkView) +``` + + +3. Initialize a `CGPoint` property in your cell (`CGPoint _lastTouch;`) to +indicate where the last tap was in the cell. + +4. Override the `UIResponder`'s `touchesBegan` method in your cell to identify +and save where the touches were so we can then start the ripple animation from +that point: + + +#### Objevctive-C ```objc - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { @@ -288,7 +322,22 @@ _inkView.usesLegacyInkRipple = NO; } ``` -5. Override the `setHighlighted` method for your cell and apply the start and stop ripple animations: +#### Swift + +```swift +override func touchesBegan(_ touches: Set, with event: UIEvent?) { + let touch = touches.first + let location = touch?.location(in: self) + lastTouch = location +} +``` + + +5. Override the `setHighlighted` method for your cell and apply the start and +stop ripple animations: + + +#### Objective-C ```objc - (void)setHighlighted:(BOOL)highlighted { @@ -301,7 +350,28 @@ _inkView.usesLegacyInkRipple = NO; } ``` -6. When the cell is reused we must make sure no outstanding ripple animations stay on the cell so we need to clear the ink before: +#### Swift + +```swift +override var isHighlighted: Bool { + set { + super.isHighlighted = newValue + if (newValue) { + inkView.startTouchBeganAnimation(at: lastTouch, completion: nil) + } else { + inkView.startTouchEndedAnimation(at: lastTouch, completion: nil) + } + } + // get... +} +``` + + +6. When the cell is reused we must make sure no outstanding ripple animations +stay on the cell so we need to clear the ink before: + + +#### Objective-C ```objc - (void)prepareForReuse { @@ -310,24 +380,60 @@ _inkView.usesLegacyInkRipple = NO; } ``` +#### Swift + +```swift +override func prepareForReuse() { + inkView.cancelAllAnimations(animated: false) + super.prepareForReuse() +} +``` + + Now there is ink in our cells! ### Self Sizing -In order to have cells self-size based on content and not rely on magic number constants to decide how big they should be, we need to follow these steps: -1. apply autoulayout constraints of our added subviews relative to each other and their superview (the cell's `contentView`). We need to make sure our constraints don't define static heights or widths but rather constraints that are relative or our cell won't calculate itself based on the dynamically sized content. +In order to have cells self-size based on content and not rely on magic number +constants to decide how big they should be, we need to follow these steps: -You can see how it is achieved in the `(void)setupConstraints` method in our example. If you'll notice there are some constraints that are set up to be accessible throughout the file: +1. Apply autoulayout constraints of our added subviews relative to each other +and their superview (the cell's `contentView`). We need to make sure our +constraints don't define static heights or widths but rather constraints that +are relative or our cell won't calculate itself based on the dynamically sized +content. +You can see how it is achieved in the `setupConstraints` method in our +example. If you'll notice there are some constraints that are set up to be +accessible throughout the file: + + + +#### Objective-C ```objc NSLayoutConstraint *_imageLeftPaddingConstraint; NSLayoutConstraint *_imageRightPaddingConstraint; NSLayoutConstraint *_imageWidthConstraint; ``` + +#### Swift +```swift +var imageLeftPaddingConstraint: NSLayoutConstraint +var imageRightPaddingConstraint: NSLayoutConstraint +var imageWidthConstraint: NSLayoutConstraint +``` + + This is in order to support the changing layout if an image is set or not. -2. Because our list cells need to fill the entire width of the collection view, we want to expose the cell's width to be settable by the view controller when the cell is set up. For that we expose a `setCellWidth` method that sets the width constraint of the `contentView`: +2. Because our list cells need to fill the entire width of the collection +view, we want to expose the cell's width to be settable by the view controller +when the cell is set up. For that we expose a `setCellWidth` method that sets +the width constraint of the `contentView`: + + +#### Objective-C ```objc - (void)setCellWidth:(CGFloat)width { _cellWidthConstraint.constant = width; @@ -335,37 +441,79 @@ This is in order to support the changing layout if an image is set or not. } ``` -and then in the collection view's `cellForItemAtIndexPath` delegate method we set the width: +#### Swift +```swift +func set(cellWidth: CGFloat) { + cellWidthConstraint.constant = cellWidth + cellWidthConstraint.isActive = true +} +``` + +and then in the collection view's `cellForItemAtIndexPath` delegate method we +set the width: + + + +#### Objective-C ```objc CGFloat cellWidth = CGRectGetWidth(collectionView.bounds); -#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) if (@available(iOS 11.0, *)) { cellWidth -= (collectionView.adjustedContentInset.left + collectionView.adjustedContentInset.right); } -#endif [cell setCellWidth:cellWidth]; ``` +#### Swift +```swift +var cellWidth = collectionView.bounds.width +if #available(iOS 11.0, *) { + cellWidth -= collectionView.adjustedContentInset.left + collectionView.adjustedContentInset.right +} +set(cellWidth: cellWidth) +``` + -3. In our collection view's flow layout we must set an `estimatedItemSize` so the collection view will defer the size calculations to its content. +3. In our collection view's flow layout we must set an `estimatedItemSize` so +the collection view will defer the size calculations to its content. -Note: It is better to set the size smaller rather than larger or constraints might break in runtime. +Note: It is better to set the size smaller rather than larger or constraints +might break in runtime. + + +#### Objective-C ```objc _flowLayout.estimatedItemSize = CGSizeMake(kSmallArbitraryCellWidth, kSmallestCellHeight); ``` +#### Swift +```swift +flowLayout.estimatedItemSize = CGSize(width: kSmallArbitraryCellWidth, + height: kSmallestCellHeight) +``` + + ### Typography -For our example we use a typography scheme to apply the fonts to our cell's `UILabel`'s. Please see Typography Scheme for more info. +For our example we use a typography scheme to apply the fonts to our cell's +`UILabel`s. Please see Typography +Scheme for more information. ### Dynamic Type -Dynamic Type allows users to indicate a system-wide preferred text size. To support it in our cells we need to follow these steps: +Dynamic +Type allows users to indicate a system-wide preferred text size. To +support it in our cells we need to follow these steps: -1. Set each of the label fonts to use the dynamically sized MDC fonts in their set/update methods: +1. Set each of the label fonts to use the dynamically sized MDC fonts in their +set/update methods: + + + +#### Objective-C ```objc - (void)updateTitleFont { if (!_titleFont) { @@ -378,8 +526,26 @@ For our example we use a typography scheme to apply the fonts to our cell's `UIL } ``` -2. Add an observer in the cell to check for the `UIContentSizeCategoryDidChangeNotification` which tells us the a system-wide text size has been changed. +#### Swift +```swift +func updateTitleFont() { + if (_titleFont == nil) { + _titleFont = defaultTitleFont + } + _titleLabel.font = + _titleFont.mdc_fontSized(forMaterialTextStyle: .subheadline, + scaledForDynamicType: mdc_adjustsFontForContentSizeCategory) +} +``` + +2. Add an observer in the cell to check for the +`UIContentSizeCategoryDidChangeNotification` which tells us the a system-wide +text size has been changed. + + + +#### Objective-C ```objc [[NSNotificationCenter defaultCenter] addObserver:self @@ -388,6 +554,16 @@ For our example we use a typography scheme to apply the fonts to our cell's `UIL object:nil]; ``` +#### Swift +```swift +NotificationCenter.default.addObserver(self, + selector: #selector(contentSizeCategoryDidChange(notification:)), + name: UIContentSizeCategory.didChangeNotification, + object: nil) +``` + + + In the selector update the font sizes to reflect the change: ```objc - (void)contentSizeCategoryDidChange:(__unused NSNotification *)notification { diff --git a/components/List/docs/create-your-own.md b/components/List/docs/create-your-own.md index b372517bd..b435b4a84 100644 --- a/components/List/docs/create-your-own.md +++ b/components/List/docs/create-your-own.md @@ -2,32 +2,66 @@ The example files can be found here List Cell Example -Our example consists of a custom `UICollectionViewController`: examples/CollectionListCellExampleTypicalUse.m -and also of a custom `UICollectionViewCell`: examples/supplemental/CollectionViewListCell.m. +Our example consists of a custom `UICollectionViewController`: examples/CollectionListCellExampleTypicalUse.m +and also of a custom `UICollectionViewCell`: examples/supplemental/CollectionViewListCell.m. -The main focus will be on the custom cell as that's where all the logic goes in, whereas the collection view and its controller are using mostly boilerplate code of setting up a simple example and collection view. +The main focus will be on the custom cell as that's where all the logic goes +in, whereas the collection view and its controller are using mostly +boilerplate code of setting up a simple example and collection view. ### Layout -For our example we will have a layout consisting of a left aligned `UIImageView`, a title text `UILabel` and a details text `UILabel`. The title text will have a max of 1 line whereas the details text can be up to 3 lines. It is important to note that neither the image nor the labels need to be set. To see more of the spec guidelines for Lists please see here: https://material.io/go/design-lists -To create our layout we used auto layout constraints that are all set up in the `(void)setupConstraints` method in our custom cell. It is important to make sure we set `translatesAutoresizingMaskIntoConstraints` to `NO` for all the views we are applying constraints on. +For our example we will have a layout consisting of a left aligned +`UIImageView`, a title text `UILabel` and a details text `UILabel`. The title +text will have a max of 1 line whereas the details text can be up to 3 lines. +It is important to note that neither the image nor the labels need to be set. +To see more of the spec guidelines for Lists please see here: https://material.io/go/design-lists + +To create our layout we used auto layout constraints that are all set up in +the `(void)setupConstraints` method in our custom cell. It is important to +make sure we set `translatesAutoresizingMaskIntoConstraints` to `NO` for all +the views we are applying constraints on. ### Ink Ripple -Interactable Material components and specifically List Cells have an ink ripple when tapped on. To add ink to your cells there are a few steps you need to take: + +Interactable Material components and specifically List Cells have an ink +ripple when tapped on. To add ink to your cells there are a few steps you need +to take: 1. Add an `MDCInkView` property to your custom cell. 2. Initialize `MDCInkView` on init and add it as a subview: + +#### Objective-C + ```objc _inkView = [[MDCInkView alloc] initWithFrame:self.bounds]; _inkView.usesLegacyInkRipple = NO; [self addSubview:_inkView]; ``` -3. Initialize a `CGPoint` property in your cell (`CGPoint _lastTouch;`) to indicate where the last tap was in the cell. +#### Swift -4. Override the `UIResponder`'s `touchesBegan` method in your cell to identify and save where the touches were so we can then start the ripple animation from that point: +```swift +let inkView = MDCInkView(frame: bounds) +inkView.usesLegacyInkRipple = false +addSubview(inkView) +``` + + +3. Initialize a `CGPoint` property in your cell (`CGPoint _lastTouch;`) to +indicate where the last tap was in the cell. + +4. Override the `UIResponder`'s `touchesBegan` method in your cell to identify +and save where the touches were so we can then start the ripple animation from +that point: + + +#### Objevctive-C ```objc - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { @@ -39,7 +73,22 @@ _inkView.usesLegacyInkRipple = NO; } ``` -5. Override the `setHighlighted` method for your cell and apply the start and stop ripple animations: +#### Swift + +```swift +override func touchesBegan(_ touches: Set, with event: UIEvent?) { + let touch = touches.first + let location = touch?.location(in: self) + lastTouch = location +} +``` + + +5. Override the `setHighlighted` method for your cell and apply the start and +stop ripple animations: + + +#### Objective-C ```objc - (void)setHighlighted:(BOOL)highlighted { @@ -52,7 +101,28 @@ _inkView.usesLegacyInkRipple = NO; } ``` -6. When the cell is reused we must make sure no outstanding ripple animations stay on the cell so we need to clear the ink before: +#### Swift + +```swift +override var isHighlighted: Bool { + set { + super.isHighlighted = newValue + if (newValue) { + inkView.startTouchBeganAnimation(at: lastTouch, completion: nil) + } else { + inkView.startTouchEndedAnimation(at: lastTouch, completion: nil) + } + } + // get... +} +``` + + +6. When the cell is reused we must make sure no outstanding ripple animations +stay on the cell so we need to clear the ink before: + + +#### Objective-C ```objc - (void)prepareForReuse { @@ -61,24 +131,60 @@ _inkView.usesLegacyInkRipple = NO; } ``` +#### Swift + +```swift +override func prepareForReuse() { + inkView.cancelAllAnimations(animated: false) + super.prepareForReuse() +} +``` + + Now there is ink in our cells! ### Self Sizing -In order to have cells self-size based on content and not rely on magic number constants to decide how big they should be, we need to follow these steps: -1. apply autoulayout constraints of our added subviews relative to each other and their superview (the cell's `contentView`). We need to make sure our constraints don't define static heights or widths but rather constraints that are relative or our cell won't calculate itself based on the dynamically sized content. +In order to have cells self-size based on content and not rely on magic number +constants to decide how big they should be, we need to follow these steps: -You can see how it is achieved in the `(void)setupConstraints` method in our example. If you'll notice there are some constraints that are set up to be accessible throughout the file: +1. Apply autoulayout constraints of our added subviews relative to each other +and their superview (the cell's `contentView`). We need to make sure our +constraints don't define static heights or widths but rather constraints that +are relative or our cell won't calculate itself based on the dynamically sized +content. +You can see how it is achieved in the `setupConstraints` method in our +example. If you'll notice there are some constraints that are set up to be +accessible throughout the file: + + + +#### Objective-C ```objc NSLayoutConstraint *_imageLeftPaddingConstraint; NSLayoutConstraint *_imageRightPaddingConstraint; NSLayoutConstraint *_imageWidthConstraint; ``` + +#### Swift +```swift +var imageLeftPaddingConstraint: NSLayoutConstraint +var imageRightPaddingConstraint: NSLayoutConstraint +var imageWidthConstraint: NSLayoutConstraint +``` + + This is in order to support the changing layout if an image is set or not. -2. Because our list cells need to fill the entire width of the collection view, we want to expose the cell's width to be settable by the view controller when the cell is set up. For that we expose a `setCellWidth` method that sets the width constraint of the `contentView`: +2. Because our list cells need to fill the entire width of the collection +view, we want to expose the cell's width to be settable by the view controller +when the cell is set up. For that we expose a `setCellWidth` method that sets +the width constraint of the `contentView`: + + +#### Objective-C ```objc - (void)setCellWidth:(CGFloat)width { _cellWidthConstraint.constant = width; @@ -86,37 +192,79 @@ This is in order to support the changing layout if an image is set or not. } ``` -and then in the collection view's `cellForItemAtIndexPath` delegate method we set the width: +#### Swift +```swift +func set(cellWidth: CGFloat) { + cellWidthConstraint.constant = cellWidth + cellWidthConstraint.isActive = true +} +``` + +and then in the collection view's `cellForItemAtIndexPath` delegate method we +set the width: + + + +#### Objective-C ```objc CGFloat cellWidth = CGRectGetWidth(collectionView.bounds); -#if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) if (@available(iOS 11.0, *)) { cellWidth -= (collectionView.adjustedContentInset.left + collectionView.adjustedContentInset.right); } -#endif [cell setCellWidth:cellWidth]; ``` +#### Swift +```swift +var cellWidth = collectionView.bounds.width +if #available(iOS 11.0, *) { + cellWidth -= collectionView.adjustedContentInset.left + collectionView.adjustedContentInset.right +} +set(cellWidth: cellWidth) +``` + -3. In our collection view's flow layout we must set an `estimatedItemSize` so the collection view will defer the size calculations to its content. +3. In our collection view's flow layout we must set an `estimatedItemSize` so +the collection view will defer the size calculations to its content. -Note: It is better to set the size smaller rather than larger or constraints might break in runtime. +Note: It is better to set the size smaller rather than larger or constraints +might break in runtime. + + +#### Objective-C ```objc _flowLayout.estimatedItemSize = CGSizeMake(kSmallArbitraryCellWidth, kSmallestCellHeight); ``` +#### Swift +```swift +flowLayout.estimatedItemSize = CGSize(width: kSmallArbitraryCellWidth, + height: kSmallestCellHeight) +``` + + ### Typography -For our example we use a typography scheme to apply the fonts to our cell's `UILabel`'s. Please see Typography Scheme for more info. +For our example we use a typography scheme to apply the fonts to our cell's +`UILabel`s. Please see Typography +Scheme for more information. ### Dynamic Type -Dynamic Type allows users to indicate a system-wide preferred text size. To support it in our cells we need to follow these steps: +Dynamic +Type allows users to indicate a system-wide preferred text size. To +support it in our cells we need to follow these steps: -1. Set each of the label fonts to use the dynamically sized MDC fonts in their set/update methods: +1. Set each of the label fonts to use the dynamically sized MDC fonts in their +set/update methods: + + + +#### Objective-C ```objc - (void)updateTitleFont { if (!_titleFont) { @@ -129,8 +277,26 @@ For our example we use a typography scheme to apply the fonts to our cell's `UIL } ``` -2. Add an observer in the cell to check for the `UIContentSizeCategoryDidChangeNotification` which tells us the a system-wide text size has been changed. +#### Swift +```swift +func updateTitleFont() { + if (_titleFont == nil) { + _titleFont = defaultTitleFont + } + _titleLabel.font = + _titleFont.mdc_fontSized(forMaterialTextStyle: .subheadline, + scaledForDynamicType: mdc_adjustsFontForContentSizeCategory) +} +``` + +2. Add an observer in the cell to check for the +`UIContentSizeCategoryDidChangeNotification` which tells us the a system-wide +text size has been changed. + + + +#### Objective-C ```objc [[NSNotificationCenter defaultCenter] addObserver:self @@ -139,6 +305,16 @@ For our example we use a typography scheme to apply the fonts to our cell's `UIL object:nil]; ``` +#### Swift +```swift +NotificationCenter.default.addObserver(self, + selector: #selector(contentSizeCategoryDidChange(notification:)), + name: UIContentSizeCategory.didChangeNotification, + object: nil) +``` + + + In the selector update the font sizes to reflect the change: ```objc - (void)contentSizeCategoryDidChange:(__unused NSNotification *)notification {