blob: 3a51f16da60b4685671f85be8b003c217665cf46 [file] [log] [blame] [edit]
// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "MDCActionSheetItemTableViewCell.h"
#import "MDCActionSheetAction.h"
#import "MaterialRipple.h" // ComponentImport
#import "MaterialTypography.h" // ComponentImport
static const CGFloat kLabelAlpha = (CGFloat)0.87;
static const CGFloat kImageTopPadding = 16;
static const CGFloat kImageHeightAndWidth = 24;
static const CGFloat kTitleLeadingPadding = 56; // 16 (layoutMargins) + 24 (image) + 16
static const CGFloat kActionItemTitleVerticalPadding = 18;
/** The height of the divider. */
static const CGFloat kDividerHeight = 1;
static inline UIColor *RippleColor(void) {
return [[UIColor alloc] initWithWhite:0 alpha:(CGFloat)0.14];
}
@interface MDCActionSheetItemTableViewCell ()
@property(nonatomic, strong) UIImageView *actionImageView;
@property(nonatomic, strong) MDCRippleTouchController *rippleTouchController;
/** Container view holding all custom content so it can be inset. */
@property(nonatomic, strong) UIView *contentContainerView;
/** A divider that is show at the top of the action. */
@property(nonatomic, strong, nonnull) UIView *divider;
@end
#ifdef __IPHONE_13_4
@interface MDCActionSheetItemTableViewCell (PointerInteractions) <UIPointerInteractionDelegate>
@end
#endif
@implementation MDCActionSheetItemTableViewCell {
MDCActionSheetAction *_itemAction;
NSLayoutConstraint *_titleLeadingConstraint;
NSLayoutConstraint *_contentContainerTopConstraint;
NSLayoutConstraint *_contentContainerLeadingConstraint;
NSLayoutConstraint *_contentContainerBottomConstraint;
NSLayoutConstraint *_contentContainerTrailingConstraint;
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self commonMDCActionSheetItemViewInit];
}
return self;
}
- (void)commonMDCActionSheetItemViewInit {
self.selectionStyle = UITableViewCellSelectionStyleNone;
self.accessibilityTraits = UIAccessibilityTraitButton;
_contentContainerView = [[UIView alloc] initWithFrame:self.bounds];
_contentContainerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:_contentContainerView];
_contentContainerTopConstraint =
[self.contentView.topAnchor constraintEqualToAnchor:_contentContainerView.topAnchor];
_contentContainerTopConstraint.active = YES;
_contentContainerLeadingConstraint = [self.contentView.layoutMarginsGuide.leadingAnchor
constraintEqualToAnchor:_contentContainerView.leadingAnchor];
_contentContainerLeadingConstraint.active = YES;
_contentContainerBottomConstraint =
[self.contentView.bottomAnchor constraintEqualToAnchor:_contentContainerView.bottomAnchor];
_contentContainerBottomConstraint.active = YES;
_contentContainerTrailingConstraint = [self.contentView.layoutMarginsGuide.trailingAnchor
constraintEqualToAnchor:_contentContainerView.trailingAnchor];
_contentContainerTrailingConstraint.active = YES;
_divider = [[UIView alloc] init];
_divider.translatesAutoresizingMaskIntoConstraints = NO;
_divider.backgroundColor = UIColor.clearColor;
[self.contentContainerView addSubview:_divider];
[_contentContainerView.topAnchor constraintEqualToAnchor:_divider.topAnchor].active = YES;
[NSLayoutConstraint constraintWithItem:_divider
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1
constant:kDividerHeight]
.active = YES;
[_contentContainerView.leadingAnchor constraintEqualToAnchor:_divider.leadingAnchor].active = YES;
[_contentContainerView.trailingAnchor constraintEqualToAnchor:_divider.trailingAnchor].active =
YES;
_actionLabel = [[UILabel alloc] init];
[_contentContainerView addSubview:_actionLabel];
_actionLabel.numberOfLines = 0;
_actionLabel.translatesAutoresizingMaskIntoConstraints = NO;
_actionLabel.font = [UIFont mdc_preferredFontForMaterialTextStyle:MDCFontTextStyleSubheadline];
_actionLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
_actionLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:kLabelAlpha];
CGFloat leadingConstant = 0;
if (_itemAction.image || _addLeadingPadding) {
leadingConstant = kTitleLeadingPadding;
}
[_actionLabel.topAnchor constraintEqualToAnchor:_contentContainerView.topAnchor
constant:kActionItemTitleVerticalPadding]
.active = YES;
[_actionLabel.bottomAnchor constraintEqualToAnchor:_contentContainerView.bottomAnchor
constant:-kActionItemTitleVerticalPadding]
.active = YES;
_titleLeadingConstraint =
[_actionLabel.leadingAnchor constraintEqualToAnchor:_contentContainerView.leadingAnchor
constant:leadingConstant];
_titleLeadingConstraint.active = YES;
[_actionLabel.trailingAnchor constraintEqualToAnchor:_contentContainerView.trailingAnchor]
.active = YES;
_rippleColor = RippleColor();
if (!_rippleTouchController) {
_rippleTouchController = [[MDCRippleTouchController alloc] init];
[_rippleTouchController addRippleToView:self];
_rippleTouchController.rippleView.rippleColor = _rippleColor;
}
_actionImageView = [[UIImageView alloc] init];
[_contentContainerView addSubview:_actionImageView];
_actionImageView.translatesAutoresizingMaskIntoConstraints = NO;
[_actionImageView.topAnchor constraintEqualToAnchor:_contentContainerView.topAnchor
constant:kImageTopPadding]
.active = YES;
[_actionImageView.leadingAnchor constraintEqualToAnchor:_contentContainerView.leadingAnchor]
.active = YES;
[_actionImageView.widthAnchor constraintEqualToConstant:kImageHeightAndWidth].active = YES;
[_actionImageView.heightAnchor constraintEqualToConstant:kImageHeightAndWidth].active = YES;
#ifdef __IPHONE_13_4
if (@available(iOS 13.4, *)) {
// Because some iOS 13 betas did not have the UIPointerInteraction class, we need to verify
// that it exists before attempting to use it.
if (NSClassFromString(@"UIPointerInteraction")) {
UIPointerInteraction *pointerInteraction =
[[UIPointerInteraction alloc] initWithDelegate:self];
[self.contentView addInteraction:pointerInteraction];
}
}
#endif
}
- (void)layoutSubviews {
[super layoutSubviews];
self.actionLabel.accessibilityLabel = _itemAction.accessibilityLabel;
self.actionLabel.text = _itemAction.title;
CGFloat leadingConstant = 0;
if (_itemAction.image || self.addLeadingPadding) {
leadingConstant = kTitleLeadingPadding;
}
_titleLeadingConstraint.constant = leadingConstant;
self.actionImageView.image = [_itemAction.image imageWithRenderingMode:self.imageRenderingMode];
}
- (void)setAction:(MDCActionSheetAction *)action {
_itemAction = [action copy];
self.actionLabel.accessibilityLabel = _itemAction.accessibilityLabel;
self.actionLabel.text = _itemAction.title;
self.actionImageView.image = _itemAction.image;
[self setNeedsLayout];
}
- (void)setContentEdgeInsets:(UIEdgeInsets)contentEdgeInsets {
_contentEdgeInsets = contentEdgeInsets;
_contentContainerTopConstraint.constant = contentEdgeInsets.top;
_contentContainerLeadingConstraint.constant = contentEdgeInsets.left;
_contentContainerBottomConstraint.constant = contentEdgeInsets.bottom;
_contentContainerTrailingConstraint.constant = contentEdgeInsets.right;
}
- (void)setDividerColor:(UIColor *)dividerColor {
self.divider.backgroundColor = dividerColor;
}
- (UIColor *)dividerColor {
return self.divider.backgroundColor;
}
- (void)setShowsDivider:(BOOL)showsDivider {
self.divider.hidden = !showsDivider;
}
- (BOOL)showsDivider {
return !self.divider.hidden;
}
- (MDCActionSheetAction *)action {
return _itemAction;
}
- (void)setActionFont:(UIFont *)actionFont {
_actionFont = actionFont;
[self updateTitleFont];
}
- (void)updateTitleFont {
UIFont *titleFont =
_actionFont ?: [UIFont mdc_standardFontForMaterialTextStyle:MDCFontTextStyleSubheadline];
self.actionLabel.font = titleFont;
[self setNeedsLayout];
}
- (void)setActionTextColor:(UIColor *)actionTextColor {
_actionTextColor = actionTextColor;
_actionLabel.textColor =
actionTextColor ?: [UIColor.blackColor colorWithAlphaComponent:kLabelAlpha];
}
- (void)setRippleColor:(UIColor *)rippleColor {
_rippleColor = rippleColor ?: RippleColor();
self.rippleTouchController.rippleView.rippleColor = _rippleColor;
}
- (void)setImageRenderingMode:(UIImageRenderingMode)imageRenderingMode {
_imageRenderingMode = imageRenderingMode;
[self setNeedsLayout];
}
#pragma mark - UIPointerInteractionDelegate
#ifdef __IPHONE_13_4
- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction
styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)) {
UIPointerStyle *pointerStyle = nil;
if (interaction.view) {
UITargetedPreview *targetedPreview = [[UITargetedPreview alloc] initWithView:interaction.view];
UIPointerEffect *hoverEffect = [UIPointerHoverEffect effectWithPreview:targetedPreview];
pointerStyle = [UIPointerStyle styleWithEffect:hoverEffect shape:nil];
}
return pointerStyle;
}
#endif
@end