// // JXCategoryTitleCell.m // UI系列测试 // // Created by jiaxin on 2018/3/15. // Copyright © 2018年 jiaxin. All rights reserved. // #import "JXCategoryTitleCell.h" #import "JXCategoryTitleCellModel.h" #import "JXCategoryFactory.h" #import "RTLManager.h" @interface JXCategoryTitleCell () @property (nonatomic, strong) CALayer *titleMaskLayer; @property (nonatomic, strong) CALayer *maskTitleMaskLayer; @property (nonatomic, strong) NSLayoutConstraint *maskTitleLabelCenterY; @end @implementation JXCategoryTitleCell - (void)initializeViews { [super initializeViews]; self.isAccessibilityElement = true; self.accessibilityTraits = UIAccessibilityTraitButton; _titleLabel = [[UILabel alloc] init]; self.titleLabel.clipsToBounds = YES; self.titleLabel.textAlignment = NSTextAlignmentCenter; self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; [self.contentView addSubview:self.titleLabel]; self.titleLabelCenterX = [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:0]; self.titleLabelCenterY = [self.titleLabel.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor constant:0]; _titleMaskLayer = [CALayer layer]; self.titleMaskLayer.backgroundColor = [UIColor redColor].CGColor; _maskTitleLabel = [[UILabel alloc] init]; self.maskTitleLabel.hidden = YES; self.maskTitleLabel.translatesAutoresizingMaskIntoConstraints = NO; self.maskTitleLabel.textAlignment = NSTextAlignmentCenter; [self.contentView addSubview:self.maskTitleLabel]; self.maskTitleLabelCenterX = [self.maskTitleLabel.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor]; self.maskTitleLabelCenterY = [self.maskTitleLabel.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor]; _maskTitleMaskLayer = [CALayer layer]; self.maskTitleMaskLayer.backgroundColor = [UIColor redColor].CGColor; self.maskTitleLabel.layer.mask = self.maskTitleMaskLayer; [NSLayoutConstraint activateConstraints:@[self.titleLabelCenterX, self.titleLabelCenterY, self.maskTitleLabelCenterX, self.maskTitleLabelCenterY]]; } - (void)layoutSubviews { [super layoutSubviews]; JXCategoryTitleCellModel *myCellModel = (JXCategoryTitleCellModel *)self.cellModel; switch (myCellModel.titleLabelAnchorPointStyle) { case JXCategoryTitleLabelAnchorPointStyleCenter: { self.titleLabel.layer.anchorPoint = CGPointMake(0.5, 0.5); self.maskTitleLabel.layer.anchorPoint = CGPointMake(0.5, 0.5); self.titleLabelCenterY.constant = 0 + myCellModel.titleLabelVerticalOffset; break; } case JXCategoryTitleLabelAnchorPointStyleTop: { self.titleLabel.layer.anchorPoint = CGPointMake(0.5, 0); self.maskTitleLabel.layer.anchorPoint = CGPointMake(0.5, 0); CGFloat percent = (myCellModel.titleLabelCurrentZoomScale - myCellModel.titleLabelNormalZoomScale)/(myCellModel.titleLabelSelectedZoomScale - myCellModel.titleLabelNormalZoomScale); self.titleLabelCenterY.constant = -myCellModel.titleHeight/2 - myCellModel.titleLabelVerticalOffset - myCellModel.titleLabelZoomSelectedVerticalOffset*percent; break; } case JXCategoryTitleLabelAnchorPointStyleBottom: { self.titleLabel.layer.anchorPoint = CGPointMake(0.5, 1); self.maskTitleLabel.layer.anchorPoint = CGPointMake(0.5, 1); CGFloat percent = (myCellModel.titleLabelCurrentZoomScale - myCellModel.titleLabelNormalZoomScale)/(myCellModel.titleLabelSelectedZoomScale - myCellModel.titleLabelNormalZoomScale); self.titleLabelCenterY.constant = myCellModel.titleHeight/2 + myCellModel.titleLabelVerticalOffset + myCellModel.titleLabelZoomSelectedVerticalOffset*percent; break; } } } - (void)reloadData:(JXCategoryBaseCellModel *)cellModel { [super reloadData:cellModel]; JXCategoryTitleCellModel *myCellModel = (JXCategoryTitleCellModel *)cellModel; self.accessibilityLabel = myCellModel.title; self.titleLabel.numberOfLines = myCellModel.titleNumberOfLines; self.maskTitleLabel.numberOfLines = myCellModel.titleNumberOfLines; if (myCellModel.isTitleLabelZoomEnabled) { //先把font设置为缩放的最大值,再缩小到最小值,最后根据当前的titleLabelZoomScale值,进行缩放更新。这样就能避免transform从小到大时字体模糊 UIFont *maxScaleFont = [UIFont fontWithDescriptor:myCellModel.titleFont.fontDescriptor size:myCellModel.titleFont.pointSize*myCellModel.titleLabelSelectedZoomScale]; CGFloat baseScale = myCellModel.titleFont.lineHeight/maxScaleFont.lineHeight; if (myCellModel.isSelectedAnimationEnabled && [self checkCanStartSelectedAnimation:myCellModel]) { JXCategoryCellSelectedAnimationBlock block = [self preferredTitleZoomAnimationBlock:myCellModel baseScale:baseScale]; [self addSelectedAnimationBlock:block]; } else { self.titleLabel.font = maxScaleFont; self.maskTitleLabel.font = maxScaleFont; CGAffineTransform currentTransform = CGAffineTransformMakeScale(baseScale*myCellModel.titleLabelCurrentZoomScale, baseScale*myCellModel.titleLabelCurrentZoomScale); self.titleLabel.transform = currentTransform; self.maskTitleLabel.transform = currentTransform; } } else { if (myCellModel.isSelected) { self.titleLabel.font = myCellModel.titleSelectedFont; self.maskTitleLabel.font = myCellModel.titleSelectedFont; } else { self.titleLabel.font = myCellModel.titleFont; self.maskTitleLabel.font = myCellModel.titleFont; } } NSString *titleString = myCellModel.title ? myCellModel.title : @""; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:titleString]; if (myCellModel.isTitleLabelStrokeWidthEnabled) { if (myCellModel.isSelectedAnimationEnabled && [self checkCanStartSelectedAnimation:myCellModel]) { JXCategoryCellSelectedAnimationBlock block = [self preferredTitleStrokeWidthAnimationBlock:myCellModel attributedString:attributedString]; [self addSelectedAnimationBlock:block]; } else { [attributedString addAttribute:NSStrokeWidthAttributeName value:@(myCellModel.titleLabelCurrentStrokeWidth) range:NSMakeRange(0, titleString.length)]; self.titleLabel.attributedText = attributedString; self.maskTitleLabel.attributedText = attributedString; } } else { self.titleLabel.attributedText = attributedString; self.maskTitleLabel.attributedText = attributedString; } if (myCellModel.isTitleLabelMaskEnabled) { self.maskTitleLabel.hidden = NO; self.titleLabel.textColor = myCellModel.titleNormalColor; self.maskTitleLabel.textColor = myCellModel.titleSelectedColor; [self.contentView setNeedsLayout]; [self.contentView layoutIfNeeded]; CGRect topMaskframe = myCellModel.backgroundViewMaskFrame; //将相对于cell的backgroundViewMaskFrame转换为相对于maskTitleLabel //使用self.bounds.size.width而不是self.contentView.bounds.size.width。因为某些情况下,会出现self.bounds是正确的,而self.contentView.bounds还是重用前的状态。 topMaskframe.origin.y = 0; CGRect bottomMaskFrame = topMaskframe; CGFloat maskStartX = 0; if (self.maskTitleLabel.bounds.size.width >= self.bounds.size.width) { topMaskframe.origin.x -= (self.maskTitleLabel.bounds.size.width -self.bounds.size.width)/2; bottomMaskFrame.size.width = self.maskTitleLabel.bounds.size.width; maskStartX = -(self.maskTitleLabel.bounds.size.width -self.bounds.size.width)/2; } else { bottomMaskFrame.size.width = self.bounds.size.width; topMaskframe.origin.x -= (self.bounds.size.width -self.maskTitleLabel.bounds.size.width)/2; maskStartX = 0; } bottomMaskFrame.origin.x = topMaskframe.origin.x; if (topMaskframe.origin.x > maskStartX) { bottomMaskFrame.origin.x = topMaskframe.origin.x - bottomMaskFrame.size.width; } else { bottomMaskFrame.origin.x = CGRectGetMaxX(topMaskframe); } // 适配RTL布局(镜像x值) if ([RTLManager supportRTL]) { topMaskframe.origin.x = self.maskTitleMaskLayer.superlayer.frame.size.width - CGRectGetMaxX(topMaskframe); bottomMaskFrame.origin.x = self.titleMaskLayer.superlayer.frame.size.width - CGRectGetMaxX(bottomMaskFrame); } [CATransaction begin]; [CATransaction setDisableActions:YES]; if (topMaskframe.size.width > 0 && CGRectIntersectsRect(topMaskframe, self.maskTitleLabel.frame)) { self.titleLabel.layer.mask = self.titleMaskLayer; self.maskTitleMaskLayer.frame = topMaskframe; self.titleMaskLayer.frame = bottomMaskFrame; } else { self.maskTitleMaskLayer.frame = topMaskframe; self.titleLabel.layer.mask = nil; } [CATransaction commit]; } else { self.maskTitleLabel.hidden = YES; self.titleLabel.layer.mask = nil; if (myCellModel.isSelectedAnimationEnabled && [self checkCanStartSelectedAnimation:myCellModel]) { JXCategoryCellSelectedAnimationBlock block = [self preferredTitleColorAnimationBlock:myCellModel]; [self addSelectedAnimationBlock:block]; } else { self.titleLabel.textColor = myCellModel.titleCurrentColor; } } [self startSelectedAnimationIfNeeded:myCellModel]; } #pragma mark - Public - (JXCategoryCellSelectedAnimationBlock)preferredTitleZoomAnimationBlock:(JXCategoryTitleCellModel *)cellModel baseScale:(CGFloat)baseScale { __weak typeof(self) weakSelf = self; return ^(CGFloat percent) { if (cellModel.isSelected) { //将要选中,scale从小到大插值渐变 cellModel.titleLabelCurrentZoomScale = [JXCategoryFactory interpolationFrom:cellModel.titleLabelNormalZoomScale to:cellModel.titleLabelSelectedZoomScale percent:percent]; } else { //将要取消选中,scale从大到小插值渐变 cellModel.titleLabelCurrentZoomScale = [JXCategoryFactory interpolationFrom:cellModel.titleLabelSelectedZoomScale to:cellModel.titleLabelNormalZoomScale percent:percent]; } CGAffineTransform currentTransform = CGAffineTransformMakeScale(baseScale*cellModel.titleLabelCurrentZoomScale, baseScale*cellModel.titleLabelCurrentZoomScale); weakSelf.titleLabel.transform = currentTransform; weakSelf.maskTitleLabel.transform = currentTransform; }; } - (JXCategoryCellSelectedAnimationBlock)preferredTitleStrokeWidthAnimationBlock:(JXCategoryTitleCellModel *)cellModel attributedString:(NSMutableAttributedString *)attributedString { __weak typeof(self) weakSelf = self; return ^(CGFloat percent) { if (cellModel.isSelected) { //将要选中,StrokeWidth从小到大插值渐变 cellModel.titleLabelCurrentStrokeWidth = [JXCategoryFactory interpolationFrom:cellModel.titleLabelNormalStrokeWidth to:cellModel.titleLabelSelectedStrokeWidth percent:percent]; } else { //将要取消选中,StrokeWidth从大到小插值渐变 cellModel.titleLabelCurrentStrokeWidth = [JXCategoryFactory interpolationFrom:cellModel.titleLabelSelectedStrokeWidth to:cellModel.titleLabelNormalStrokeWidth percent:percent]; } [attributedString addAttribute:NSStrokeWidthAttributeName value:@(cellModel.titleLabelCurrentStrokeWidth) range:NSMakeRange(0, attributedString.string.length)]; weakSelf.titleLabel.attributedText = attributedString; weakSelf.maskTitleLabel.attributedText = attributedString; }; } - (JXCategoryCellSelectedAnimationBlock)preferredTitleColorAnimationBlock:(JXCategoryTitleCellModel *)cellModel { __weak typeof(self) weakSelf = self; return ^(CGFloat percent) { if (cellModel.isSelected) { //将要选中,textColor从titleNormalColor到titleSelectedColor插值渐变 cellModel.titleCurrentColor = [JXCategoryFactory interpolationColorFrom:cellModel.titleNormalColor to:cellModel.titleSelectedColor percent:percent]; } else { //将要取消选中,textColor从titleSelectedColor到titleNormalColor插值渐变 cellModel.titleCurrentColor = [JXCategoryFactory interpolationColorFrom:cellModel.titleSelectedColor to:cellModel.titleNormalColor percent:percent]; } weakSelf.titleLabel.textColor = cellModel.titleCurrentColor; }; } @end