123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- //
- // JXSegmentedTitleCell.swift
- // JXSegmentedView
- //
- // Created by jiaxin on 2018/12/26.
- // Copyright © 2018 jiaxin. All rights reserved.
- //
- import UIKit
- open class JXSegmentedTitleCell: JXSegmentedBaseCell {
- public let titleLabel = UILabel()
- public let maskTitleLabel = UILabel()
- public let titleMaskLayer = CALayer()
- public let maskTitleMaskLayer = CALayer()
- open override func commonInit() {
- super.commonInit()
- titleLabel.textAlignment = .center
- contentView.addSubview(titleLabel)
- maskTitleLabel.textAlignment = .center
- maskTitleLabel.isHidden = true
- contentView.addSubview(maskTitleLabel)
- titleMaskLayer.backgroundColor = UIColor.red.cgColor
- maskTitleMaskLayer.backgroundColor = UIColor.red.cgColor
- maskTitleLabel.layer.mask = maskTitleMaskLayer
- }
- open override func layoutSubviews() {
- super.layoutSubviews()
- //为什么使用`sizeThatFits`,而不用`sizeToFit`呢?在numberOfLines大于0的时候,cell进行重用的时候通过`sizeToFit`,label设置成错误的size。至于原因我用尽毕生所学,没有找到为什么。但是用`sizeThatFits`可以规避掉这个问题。
- let labelSize = titleLabel.sizeThatFits(self.contentView.bounds.size)
- let labelBounds = CGRect(x: 0, y: 0, width: labelSize.width, height: labelSize.height)
- titleLabel.bounds = labelBounds
- titleLabel.center = contentView.center
- maskTitleLabel.bounds = labelBounds
- maskTitleLabel.center = contentView.center
- }
- open override func reloadData(itemModel: JXSegmentedBaseItemModel, selectedType: JXSegmentedViewItemSelectedType) {
- super.reloadData(itemModel: itemModel, selectedType: selectedType )
- guard let myItemModel = itemModel as? JXSegmentedTitleItemModel else {
- return
- }
- titleLabel.numberOfLines = myItemModel.titleNumberOfLines
- maskTitleLabel.numberOfLines = myItemModel.titleNumberOfLines
- if myItemModel.isTitleZoomEnabled {
- //先把font设置为缩放的最大值,再缩小到最小值,最后根据当前的titleCurrentZoomScale值,进行缩放更新。这样就能避免transform从小到大时字体模糊
- let maxScaleFont = UIFont(descriptor: myItemModel.titleNormalFont.fontDescriptor, size: myItemModel.titleNormalFont.pointSize*CGFloat(myItemModel.titleSelectedZoomScale))
- let baseScale = myItemModel.titleNormalFont.lineHeight/maxScaleFont.lineHeight
- if myItemModel.isSelectedAnimable && canStartSelectedAnimation(itemModel: itemModel, selectedType: selectedType) {
- //允许动画且当前是点击的
- let titleZoomClosure = preferredTitleZoomAnimateClosure(itemModel: myItemModel, baseScale: baseScale)
- appendSelectedAnimationClosure(closure: titleZoomClosure)
- }else {
- titleLabel.font = maxScaleFont
- maskTitleLabel.font = maxScaleFont
- let currentTransform = CGAffineTransform(scaleX: baseScale*CGFloat(myItemModel.titleCurrentZoomScale), y: baseScale*CGFloat(myItemModel.titleCurrentZoomScale))
- titleLabel.transform = currentTransform
- maskTitleLabel.transform = currentTransform
- }
- }else {
- if myItemModel.isSelected {
- titleLabel.font = myItemModel.titleSelectedFont
- maskTitleLabel.font = myItemModel.titleSelectedFont
- }else {
- titleLabel.font = myItemModel.titleNormalFont
- maskTitleLabel.font = myItemModel.titleNormalFont
- }
- }
- let title = myItemModel.title ?? ""
- let attriText = NSMutableAttributedString(string: title)
- if myItemModel.isTitleStrokeWidthEnabled {
- if myItemModel.isSelectedAnimable && canStartSelectedAnimation(itemModel: itemModel, selectedType: selectedType) {
- //允许动画且当前是点击的
- let titleStrokeWidthClosure = preferredTitleStrokeWidthAnimateClosure(itemModel: myItemModel, attriText: attriText)
- appendSelectedAnimationClosure(closure: titleStrokeWidthClosure)
- }else {
- attriText.addAttributes([NSAttributedString.Key.strokeWidth: myItemModel.titleCurrentStrokeWidth], range: NSRange(location: 0, length: title.count))
- titleLabel.attributedText = attriText
- maskTitleLabel.attributedText = attriText
- }
- }else {
- titleLabel.attributedText = attriText
- maskTitleLabel.attributedText = attriText
- }
- if myItemModel.isTitleMaskEnabled {
- //允许mask,maskTitleLabel在titleLabel上面,maskTitleLabel设置为titleSelectedColor。titleLabel设置为titleNormalColor
- //为了显示效果,使用了双遮罩。即titleMaskLayer遮罩titleLabel,maskTitleMaskLayer遮罩maskTitleLabel
- maskTitleLabel.isHidden = false
- titleLabel.textColor = myItemModel.titleNormalColor
- maskTitleLabel.textColor = myItemModel.titleSelectedColor
- let labelSize = maskTitleLabel.sizeThatFits(self.contentView.bounds.size)
- let labelBounds = CGRect(x: 0, y: 0, width: labelSize.width, height: labelSize.height)
- maskTitleLabel.bounds = labelBounds
- var topMaskFrame = myItemModel.indicatorConvertToItemFrame
- topMaskFrame.origin.y = 0
- var bottomMaskFrame = topMaskFrame
- var maskStartX: CGFloat = 0
- if maskTitleLabel.bounds.size.width >= bounds.size.width {
- topMaskFrame.origin.x -= (maskTitleLabel.bounds.size.width - bounds.size.width)/2
- bottomMaskFrame.size.width = maskTitleLabel.bounds.size.width
- maskStartX = -(maskTitleLabel.bounds.size.width - bounds.size.width)/2
- }else {
- topMaskFrame.origin.x -= (bounds.size.width - maskTitleLabel.bounds.size.width)/2
- bottomMaskFrame.size.width = bounds.size.width
- 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 = topMaskFrame.maxX
- }
- CATransaction.begin()
- CATransaction.setDisableActions(true)
- if topMaskFrame.size.width > 0 && topMaskFrame.intersects(maskTitleLabel.frame) {
- titleLabel.layer.mask = titleMaskLayer
- titleMaskLayer.frame = bottomMaskFrame
- maskTitleMaskLayer.frame = topMaskFrame
- }else {
- titleLabel.layer.mask = nil
- maskTitleMaskLayer.frame = topMaskFrame
- }
- CATransaction.commit()
- }else {
- maskTitleLabel.isHidden = true
- titleLabel.layer.mask = nil
- if myItemModel.isSelectedAnimable && canStartSelectedAnimation(itemModel: itemModel, selectedType: selectedType) {
- //允许动画且当前是点击的
- let titleColorClosure = preferredTitleColorAnimateClosure(itemModel: myItemModel)
- appendSelectedAnimationClosure(closure: titleColorClosure)
- }else {
- titleLabel.textColor = myItemModel.titleCurrentColor
- }
- }
- startSelectedAnimationIfNeeded(itemModel: itemModel, selectedType: selectedType)
- setNeedsLayout()
- }
- open func preferredTitleZoomAnimateClosure(itemModel: JXSegmentedTitleItemModel, baseScale: CGFloat) -> JXSegmentedCellSelectedAnimationClosure {
- return {[weak self] (percnet) in
- if itemModel.isSelected {
- //将要选中,scale从小到大插值渐变
- itemModel.titleCurrentZoomScale = JXSegmentedViewTool.interpolate(from: itemModel.titleNormalZoomScale, to: itemModel.titleSelectedZoomScale, percent: percnet)
- }else {
- //将要取消选中,scale从大到小插值渐变
- itemModel.titleCurrentZoomScale = JXSegmentedViewTool.interpolate(from: itemModel.titleSelectedZoomScale, to:itemModel.titleNormalZoomScale , percent: percnet)
- }
- let currentTransform = CGAffineTransform(scaleX: baseScale*itemModel.titleCurrentZoomScale, y: baseScale*itemModel.titleCurrentZoomScale)
- self?.titleLabel.transform = currentTransform
- self?.maskTitleLabel.transform = currentTransform
- }
- }
- open func preferredTitleStrokeWidthAnimateClosure(itemModel: JXSegmentedTitleItemModel, attriText: NSMutableAttributedString) -> JXSegmentedCellSelectedAnimationClosure{
- return {[weak self] (percent) in
- if itemModel.isSelected {
- //将要选中,StrokeWidth从小到大插值渐变
- itemModel.titleCurrentStrokeWidth = JXSegmentedViewTool.interpolate(from: itemModel.titleNormalStrokeWidth, to: itemModel.titleSelectedStrokeWidth, percent: percent)
- }else {
- //将要取消选中,StrokeWidth从大到小插值渐变
- itemModel.titleCurrentStrokeWidth = JXSegmentedViewTool.interpolate(from: itemModel.titleSelectedStrokeWidth, to:itemModel.titleNormalStrokeWidth , percent: percent)
- }
- attriText.addAttributes([NSAttributedString.Key.strokeWidth: itemModel.titleCurrentStrokeWidth], range: NSRange(location: 0, length: attriText.string.count))
- self?.titleLabel.attributedText = attriText
- self?.maskTitleLabel.attributedText = attriText
- }
- }
- open func preferredTitleColorAnimateClosure(itemModel: JXSegmentedTitleItemModel) -> JXSegmentedCellSelectedAnimationClosure {
- return {[weak self] (percent) in
- if itemModel.isSelected {
- //将要选中,textColor从titleNormalColor到titleSelectedColor插值渐变
- itemModel.titleCurrentColor = JXSegmentedViewTool.interpolateColor(from: itemModel.titleNormalColor, to: itemModel.titleSelectedColor, percent: percent)
- }else {
- //将要取消选中,textColor从titleSelectedColor到titleNormalColor插值渐变
- itemModel.titleCurrentColor = JXSegmentedViewTool.interpolateColor(from: itemModel.titleSelectedColor, to: itemModel.titleNormalColor, percent: percent)
- }
- self?.titleLabel.textColor = itemModel.titleCurrentColor
- }
- }
- }
|