Skip to content

Instantly share code, notes, and snippets.

@descorp
Created November 22, 2019 13:33
Show Gist options
  • Save descorp/fdc759525e2a6d1f180a498cad966d28 to your computer and use it in GitHub Desktop.
Save descorp/fdc759525e2a6d1f180a498cad966d28 to your computer and use it in GitHub Desktop.
Swift TagCloudCollectionView
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class EdgeInsetLabel: UILabel {
private let textInsets: UIEdgeInsets
init(inset: UIEdgeInsets) {
textInsets = inset
super.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
let insetRect = bounds.inset(by: textInsets)
let textRect = super.textRect(forBounds: insetRect, limitedToNumberOfLines: numberOfLines)
let invertedInsets = UIEdgeInsets(top: -textInsets.top,
left: -textInsets.left,
bottom: -textInsets.bottom,
right: -textInsets.right)
return textRect.inset(by: invertedInsets)
}
override func drawText(in rect: CGRect) {
super.drawText(in: rect.inset(by: textInsets))
}
}
class MyCell: UICollectionViewCell {
lazy var titleLabel: UILabel = {
let view = EdgeInsetLabel(inset: UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 8))
view.font = .systemFont(ofSize: 16)
view.frame = self.contentView.frame
view.backgroundColor = .systemFill
self.contentView.addSubview(view)
return view
}()
func set(title: String) {
titleLabel.text = title
clipsToBounds = true
}
override func draw(_ rect: CGRect) {
super.draw(rect)
layer.cornerRadius = rect.height / 2
}
}
class FlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributesForElementsInRect = super.layoutAttributesForElements(in: rect) else { return nil }
var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
// use a value to keep track of left margin
var leftMargin: CGFloat = 0.0;
var topMargin: CGFloat = 0.0;
for refAttributes in attributesForElementsInRect {
// If element on a next line
if topMargin != refAttributes.frame.origin.y {
topMargin = refAttributes.frame.origin.y
leftMargin = self.sectionInset.left // Start from the begining
}
// Modify frame for current refAttributes
var newLeftAlignedFrame = refAttributes.frame
newLeftAlignedFrame.origin.x = leftMargin
refAttributes.frame = newLeftAlignedFrame
// Calculate for next element in a line
leftMargin += refAttributes.frame.size.width + minimumInteritemSpacing
newAttributesForElementsInRect.append(refAttributes)
}
return newAttributesForElementsInRect
}
}
class MyViewController : UIViewController {
var data = ["Aruba ⤫", "Afghanistan ⤫", "Africa ⤫", "Angola ⤫", "Albania ⤫", "Andorra ⤫", "Andean region ⤫", "Arab World ⤫", "United Arab Emirates ⤫", "Argentina ⤫", "Armenia ⤫", "American Samoa ⤫", "Antigua and Barbuda ⤫"].shuffled()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let layout = FlowLayout()
layout.scrollDirection = .vertical
layout.minimumInteritemSpacing = 8
layout.sectionInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
let collection = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.addSubview(collection)
collection.register(MyCell.self, forCellWithReuseIdentifier: "cell")
collection.backgroundColor = .systemGray4
collection.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collection.dataSource = self
collection.delegate = self
self.view = view
}
}
extension MyViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
if let cell = cell as? MyCell {
cell.set(title: data[indexPath.item])
}
return cell
}
}
extension MyViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
data.remove(at: indexPath.item)
collectionView.deleteItems(at: [indexPath])
collectionView.collectionViewLayout.invalidateLayout()
}
}
extension MyViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let attributes = [ NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16)]
var size = data[indexPath.item].size(withAttributes: attributes)
size.height = size.height + 16
size.width = size.width + 32
return size
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
@descorp
Copy link
Author

descorp commented Nov 22, 2019

Nov-22-2019 14-29-11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment