效果图:
代码
import UIKit
let SCREEN_WIDTH = UIScreen.main.bounds.size.width
let SCREEN_HEIGHT = UIScreen.main.bounds.size.height
class CYNewPlayViewController: UIViewController {
private var collectionView: UICollectionView!
private lazy var indicatorView = UIView()
private var dataList: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
dataList = ["cyan1","cyan2","cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3cyan3","cyan4","cyan5","cyan6"]
initialAppearance()
}
private func initialAppearance() {
view.backgroundColor = .white
let layout = MineDecorationFlowlayout(with: MineDecorationView.self)
layout.dc_delegate = self
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.size.width, height: 100)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CYCollectionViewCell.self, forCellWithReuseIdentifier: "CYCollectionViewCell")
collectionView.backgroundColor = .gray
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
view.addSubview(collectionView)
self.collectionView = collectionView
collectionView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
}
}
// MARK: - UICollectionViewDelegate
extension CYNewPlayViewController: UICollectionViewDelegate, UICollectionViewDataSource, MineDecorationFlowlayoutDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0: return 1
default: return dataList.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CYCollectionViewCell", for: indexPath) as! CYCollectionViewCell
let title = dataList[indexPath.item]
cell.titleLabel.text = title
// 设置圆角样式
if indexPath.section == 0 {
cell.locationType = .all
} else {
switch indexPath.item {
case 0: cell.locationType = .top
case dataList.count - 1: cell.locationType = .bottom
default: cell.locationType = .middle
}
}
return cell
}
func layout(_ layout: MineDecorationFlowlayout, decorationImageAt section: Int) -> String {
return ""
}
func layout(_ layout: MineDecorationFlowlayout, decorationImageAt indexPath: IndexPath) -> String {
return ""
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 15, left: 0, bottom: 0, right: 0)
}
}
// MARK: - cell
class CYCollectionViewCell: UICollectionViewCell {
/// cell圆角位置
enum CYCellLocationType {
case top // 头部圆角
case middle // 无圆角
case bottom // 底部圆角
case all // 全圆角
}
var bgView = UIView()
var titleLabel = UILabel()
var locationType: CYCellLocationType = .middle {
didSet {
self.setNeedsLayout()
self.layoutIfNeeded()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
initialAppearance()
}
override func layoutSubviews() {
super.layoutSubviews()
contentView.setNeedsLayout()
contentView.layoutIfNeeded()
reloadBgView(locationType)
}
private func reloadBgView(_ type: CYCellLocationType) {
let size = CGSize(width: 10, height: 10)
var corners: UIRectCorner = []
switch type {
case .top: corners = [.topLeft, .topRight]
case .bottom: corners = [.bottomLeft, .bottomRight]
case .all: corners = [.allCorners]
default:
break
}
//设置mask
let mask = bgView.viewMaskWithBounds(bounds: bgView.bounds, corners: corners, cornerRadii: size)
bgView.layer.mask = mask
}
func initialAppearance() {
bgView.backgroundColor = UIColor.systemGray
bgView.isHidden = true
self.contentView.addSubview(bgView)
titleLabel.font = UIFont.systemFont(ofSize: 16)
titleLabel.numberOfLines = 0
self.contentView.addSubview(titleLabel)
bgView.snp.makeConstraints { (make) in
make.left.equalToSuperview().offset(12)
make.right.equalToSuperview().offset(-12)
make.top.bottom.equalToSuperview()
}
titleLabel.snp.makeConstraints { (make) in
make.left.top.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.bottom.equalToSuperview().offset(-15)
}
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
self.setNeedsLayout()
self.layoutIfNeeded()
let size = self.contentView.systemLayoutSizeFitting(layoutAttributes.size)
var cellFrame = layoutAttributes.frame
cellFrame.size.height = size.height
layoutAttributes.frame = cellFrame
return layoutAttributes
}
// MARK: - 选中效果相关
private var isSelect: Bool = false
private var isHighlight: Bool = false
override var isSelected: Bool {
set {
self.isSelect = newValue
self.bgView.isHidden = !newValue
}
get {
return self.isSelect
}
}
override var isHighlighted: Bool {
set {
self.isHighlight = newValue
self.bgView.isHidden = !newValue
}
get {
return self.isHighlight
}
}
}
// MARK: - MineDecorationView
class MineDecorationView: UICollectionReusableView {
lazy var imageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
imageView.layer.cornerRadius = 10
imageView.backgroundColor = .white
addSubview(imageView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
let frame = CGRect(x: 12, y: 0, width: layoutAttributes.bounds.width - 24, height: layoutAttributes.bounds.height)
imageView.frame = frame
guard let attributes = layoutAttributes as? MineDecorationAttributes, let imageName = attributes.imageName, !imageName.isEmpty else { return }
imageView.image = UIImage(named: imageName)
}
}
// MARK: - MineDecorationAttributes
class MineDecorationAttributes: UICollectionViewLayoutAttributes {
var imageName: String?
}
// MARK: - MineDecorationFlowlayout
protocol MineDecorationFlowlayoutDelegate: UICollectionViewDelegateFlowLayout {
func layout(_ layout: MineDecorationFlowlayout, decorationImageAt section: Int) -> String
func layout(_ layout: MineDecorationFlowlayout, decorationImageAt indexPath: IndexPath) -> String
}
class MineDecorationFlowlayout: UICollectionViewFlowLayout {
let decorationViewKind: String
let viewType: AnyClass
var itemsAttribute: [UICollectionViewLayoutAttributes] = []
weak var dc_delegate: MineDecorationFlowlayoutDelegate?
init(with viewKind: UICollectionReusableView.Type) {
decorationViewKind = String(describing: viewKind)
viewType = viewKind
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
super.prepare()
self.register(viewType, forDecorationViewOfKind: decorationViewKind)
self.itemsAttribute.removeAll()
let sections = self.collectionView?.numberOfSections ?? 0
// 给section添加一张背景图片
for i in 0..<sections {
let attribute = MineDecorationAttributes(forDecorationViewOfKind: decorationViewKind, with: IndexPath(item: 0, section: i))
attribute.zIndex = -1
attribute.imageName = dc_delegate?.layout(self, decorationImageAt: i)
if let count = self.collectionView?.numberOfItems(inSection: i), count > 0 {
let firstItem = self.layoutAttributesForItem(at: IndexPath(item: 0, section: i))
let lastItem = self.layoutAttributesForItem(at: IndexPath(item: (count - 1), section: i))
let height = lastItem!.frame.maxY - firstItem!.frame.minY
attribute.frame = CGRect(x: 0, y: firstItem!.frame.minY, width: self.collectionView!.frame.size.width, height: height)
self.itemsAttribute.append(attribute)
}
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributes = super.layoutAttributesForElements(in: rect)
for attribute in self.itemsAttribute {
if rect.intersects(attribute.frame) {
attributes?.append(attribute)
}
}
return attributes
}
}
extension UIView {
/**
let size = CGSize(width: 3, height: 3)
//设置layer
let layer = self.showImageV.viewLayerWithBounds(bounds: self.showImageV.bounds, corners: [.topLeft, .topRight], cornerRadii: size, color: UIColor.clear)
//设置mask
let mask = self.showImageV.viewMaskWithBounds(bounds: self.showImageV.bounds, corners: [.topLeft, .topRight], cornerRadii: size)
self.showImageV.layer.addSublayer(layer)
self.showImageV.layer.mask = mask
*注 在使用masnory 的时候 需要在layoutSubviews 方法后增加
contentView.setNeedsLayout()
contentView.layoutIfNeeded()
防止bounds为空
*/
func viewLayerWithBounds(bounds: CGRect,corners: UIRectCorner,cornerRadii : CGSize,color: UIColor?) -> CALayer {
let maskPath3 = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: cornerRadii)
let borderLayer3 = CAShapeLayer.init()
borderLayer3.frame = bounds
borderLayer3.path = maskPath3.cgPath
if color == nil {
borderLayer3.strokeColor = UIColor.init(red: 228.0 / 255, green: 228.0 / 255, blue: 228.0 / 255, alpha: 1).cgColor
}else {
borderLayer3.strokeColor = color?.cgColor
}
borderLayer3.fillColor = UIColor.clear.cgColor
borderLayer3.lineWidth = 2.0
borderLayer3.lineDashPattern = [4,2]
return borderLayer3
}
func viewMaskWithBounds(bounds: CGRect,corners: UIRectCorner,cornerRadii : CGSize) -> CALayer {
let maskPath3 = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: cornerRadii)
let maskLayer3 = CAShapeLayer()
maskLayer3.frame = bounds
maskLayer3.path = maskPath3.cgPath
return maskLayer3
}
}