swift 您所在的位置:网站首页 swift课程介绍 swift

swift

2023-03-07 11:01| 来源: 网络整理| 查看: 265

最终效果:

实现思路: 

1、关键点:

a. cell高度自适应

b. 自定义viewController实现代理,方便与cell交互,记录cell折叠/展开的状态进行展示

2、具体思路图示:

demo如下:

1、创建CollectionViewTextExpansionCell.swift文件,代码如下:

import UIKit class CollectionViewTextExpansionCell: UICollectionViewCell { // 渲染cell的内容 public var model: (String, String)? { didSet { guard let model = self.model else { return } self.titleLabel.text = model.0 self.subTitlLabel.text = model.1 } } // 记录展开折叠的状态 public var isUnfold: Bool = false { didSet { if (self.isUnfold) { self.subTitlLabel.numberOfLines = 0 } else { self.subTitlLabel.numberOfLines = 3 } self.foldBtn.isSelected = self.isUnfold } } // 记录文字是否显示完全 public var isTruncated: Bool = false { didSet { self.foldBtn.isHidden = !self.isTruncated } } public var delegate: CollectionViewTextExpansionCellDelegate? private var titleLabel: UILabel = UILabel() private var subTitlLabel: UILabel = UILabel() private var foldBtn: UIButton = UIButton() override init(frame: CGRect) { super.init(frame: frame) self.setupUI() } override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { self.setNeedsLayout() self.layoutIfNeeded() // 判断subTitle实际所需的行数 let maxSize = CGRect(origin: self.subTitlLabel.frame.origin, size: CGSize(width: self.subTitlLabel.bounds.width, height: CGFloat(MAXFLOAT))) let realSize = self.subTitlLabel.textRect(forBounds: maxSize, limitedToNumberOfLines: 0).size let labelTextLines = Int(realSize.height / self.subTitlLabel.font.lineHeight) self.isTruncated = ((!self.isUnfold && labelTextLines > 3) || self.isUnfold) let subStrings = self.getStringPerLine(in: self.subTitlLabel) let characterLength = CGFloat(subStrings[subStrings.count-1].count) / CGFloat(subStrings[0].count) let freeWidth = (1-characterLength)*self.subTitlLabel.bounds.width if (self.isUnfold && freeWidth < self.foldBtn.bounds.width) { self.subTitlLabel.snp.remakeConstraints { make in make.left.equalTo(self.titleLabel.snp.right).offset(15) make.right.equalToSuperview().offset(-15) make.top.equalToSuperview().offset(15) } self.foldBtn.snp.remakeConstraints { make in make.top.equalTo(self.subTitlLabel.snp.bottom) make.right.equalTo(self.subTitlLabel.snp.right) make.bottom.equalToSuperview() } } else { self.subTitlLabel.snp.remakeConstraints { make in make.left.equalTo(self.titleLabel.snp.right).offset(15) make.right.equalToSuperview().offset(-15) make.top.equalToSuperview().offset(15) make.bottom.equalToSuperview().offset(-15) } self.foldBtn.snp.remakeConstraints { make in make.right.bottom.equalTo(self.subTitlLabel) make.height.equalTo(13) } } // 重新计算contentView的高度 let size = self.contentView.systemLayoutSizeFitting(layoutAttributes.size) var cellFrame = layoutAttributes.frame cellFrame.size.height = size.height layoutAttributes.frame = cellFrame return layoutAttributes } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setupUI() { self.backgroundColor = .white self.contentView.addSubview(self.titleLabel) self.titleLabel.snp.makeConstraints{ make in make.left.equalToSuperview().offset(15) make.centerY.equalToSuperview() make.width.equalTo(50) } self.titleLabel.textColor = .black self.titleLabel.font = .systemFont(ofSize: 17, weight: .medium) self.titleLabel.numberOfLines = 1 self.contentView.addSubview(self.subTitlLabel) self.subTitlLabel.snp.makeConstraints { make in make.left.equalTo(self.titleLabel.snp.right).offset(15) make.right.equalToSuperview().offset(-15) make.top.equalToSuperview().offset(15) make.bottom.equalToSuperview().offset(-15) } self.subTitlLabel.textAlignment = .justified self.subTitlLabel.textColor = .darkGray self.subTitlLabel.font = .systemFont(ofSize: 13) if (self.isUnfold) { self.subTitlLabel.numberOfLines = 0 } else { self.subTitlLabel.numberOfLines = 3 } self.contentView.addSubview(self.foldBtn) self.foldBtn.snp.makeConstraints { make in make.right.bottom.equalTo(self.subTitlLabel) make.height.equalTo(13) } self.foldBtn.backgroundColor = .white self.foldBtn.setAttributedTitle(NSAttributedString(string: " 展开", attributes: [.foregroundColor: UIColor.blue, .font: UIFont.systemFont(ofSize: 13)]), for: .normal) self.foldBtn.setAttributedTitle(NSAttributedString(string: " 折叠", attributes: [.foregroundColor: UIColor.blue, .font: UIFont.systemFont(ofSize: 13)]), for: .selected) self.foldBtn.addTarget(self, action: #selector(foldEvent), for: .touchUpInside) self.foldBtn.isHidden = !self.isTruncated } @objc func foldEvent() { self.delegate?.clickFoldBtn(at: self.tag, for: !self.isUnfold) } // 获取UILabel中每一行的内容 func getStringPerLine(in label: UILabel) -> [String] { guard let text = label.text else { return [] } var result: [String] = [] let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping let attstr = NSMutableAttributedString(string: text, attributes: [NSAttributedString.Key.font: label.font]) let frameSetter = CTFramesetterCreateWithAttributedString(attstr as CFAttributedString) let path = CGMutablePath() path.addRect(CGRect(x: 0, y: 0, width: label.frame.size.width, height: label.frame.size.height)) let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) if let lines = CTFrameGetLines(frame) as? [CTLine] { lines.forEach({ let linerange = CTLineGetStringRange($0) let range = NSMakeRange(linerange.location, linerange.length) let string = (text as NSString).substring(with: range) result.append(string) }) } return result } }

2、定义代理CollectionViewTextExpansionCellDelegate

protocol CollectionViewTextExpansionCellDelegate { func clickFoldBtn(at section: Int, for state: Bool) }

3、创建CollectionViewTextExpansionViewController.swift文件,代码如下:

import UIKit class CollectionViewTextExpansionViewController: UIViewController { // MARK: - 定义collectionView public lazy var collectionView: UICollectionView = { [weak self] in // 设置collectionView的布局 let flowLayout = UICollectionViewFlowLayout() flowLayout.scrollDirection = .vertical flowLayout.minimumLineSpacing = 0 flowLayout.minimumInteritemSpacing = 0 flowLayout.sectionInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0) // 这里定义flowLayout的预估大小 flowLayout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 50) let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) collectionView.autoresizingMask = [.flexibleHeight] collectionView.showsVerticalScrollIndicator = false collectionView.delegate = self collectionView.dataSource = self collectionView.register(CollectionViewTextExpansionCell.self, forCellWithReuseIdentifier: "CollectionViewTextExpansionCell") return collectionView }() // 记录展开的cell信息 public var unfoldItems: [Int] = [] // MARK: - 模拟数据 public var list: [(String, String)] = [ ("标题1", "介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字"), ("标题2", "介绍文字介绍文字介绍文字介绍文字"), ("标题3", "介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字"), ("标题4", "介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字"), ("标题5", "介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文字介绍文"), ] // MARK: - setup UI override func viewDidLoad() { super.viewDidLoad() self.setupUI() } func setupUI() { self.title = "collectionView高度自适应-折叠版" self.collectionView.backgroundColor = UIColor(red: 248/155.0, green: 248/255.0, blue: 248/255.0, alpha: 1.0) // 添加collectionView self.view.addSubview(self.collectionView) self.collectionView.snp.makeConstraints { make in make.edges.equalToSuperview() } } } // MARK: - 实现CollectionView的代理和数据源 extension CollectionViewTextExpansionViewController : UICollectionViewDelegate, UICollectionViewDataSource { func numberOfSections(in collectionView: UICollectionView) -> Int { return self.list.count } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 1 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewTextExpansionCell", for: indexPath) as! CollectionViewTextExpansionCell cell.model = self.list[indexPath.section] cell.delegate = self cell.tag = indexPath.section cell.isUnfold = self.unfoldItems.contains(where: {$0==indexPath.section}) return cell } } // MARK: - 点击”折叠展开“按钮的代理 extension CollectionViewTextExpansionViewController: CollectionViewTextExpansionCellDelegate { func clickFoldBtn(at section: Int, for state: Bool) { if (state) { self.unfoldItems.append(section) } else { let index = self.unfoldItems.firstIndex(where: {$0==section}) if (index != nil) { self.unfoldItems.remove(at: index!) } } self.collectionView.reloadData() } }



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有