Skip to content

Commit c1de9a7

Browse files
bug fix
1 parent db9e7f8 commit c1de9a7

46 files changed

Lines changed: 2803 additions & 481 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Example/ButtonClickStyle.xcodeproj/project.pbxproj

Lines changed: 204 additions & 4 deletions
Large diffs are not rendered by default.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//
2+
// ColletionAdapterCell.swift
3+
// PatternsSwift
4+
//
5+
// Created by mrustaa on 01/05/2020.
6+
// Copyright © 2020 mrustaa. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class CollectionAdapterCell: UICollectionViewCell {
12+
13+
open var didScrollCallback: (() -> ())? = nil
14+
15+
@IBInspectable var hideAnimation: Bool = false
16+
var selectedView: UIView?
17+
18+
public var cellData: CollectionAdapterCellData?
19+
20+
open func fill(data: Any?) {
21+
22+
}
23+
24+
override init(frame: CGRect) {
25+
super.init(frame: frame)
26+
setupCommonProperties()
27+
}
28+
29+
required init?(coder: NSCoder) {
30+
super.init(coder: coder)
31+
setupCommonProperties()
32+
}
33+
34+
private func setupCommonProperties() {
35+
36+
}
37+
38+
let selAlpha: CGFloat = 0.2
39+
40+
override var isSelected: Bool {
41+
set {
42+
super.isSelected = newValue
43+
if hideAnimation {
44+
if newValue {
45+
alpha = 0.5
46+
UIView.animate(withDuration: 0.45, animations: {
47+
self.alpha = 1
48+
})
49+
} else {
50+
self.alpha = 1
51+
}
52+
} else {
53+
guard let selectedView = selectedView else { return }
54+
if newValue {
55+
selectedView.alpha = selAlpha
56+
UIView.animate(withDuration: 0.45, animations: {
57+
selectedView.alpha = 0.0
58+
})
59+
} else {
60+
selectedView.alpha = 0.0
61+
}
62+
}
63+
}
64+
get {
65+
return super.isSelected
66+
}
67+
}
68+
69+
override var isHighlighted: Bool {
70+
set {
71+
super.isHighlighted = newValue
72+
if hideAnimation {
73+
UIView.animate(withDuration: newValue ? 0.1 : 0.45, animations: {
74+
self.alpha = (newValue ? 0.0 : 1.0)
75+
})
76+
} else {
77+
guard let selectedView = selectedView else { return }
78+
if newValue {
79+
UIView.animate(withDuration: 0.1, animations: {
80+
selectedView.alpha = self.selAlpha
81+
})
82+
} else {
83+
UIView.animate(withDuration: 0.45, animations: {
84+
selectedView.alpha = 0.0
85+
})
86+
}
87+
}
88+
}
89+
get { super.isHighlighted }
90+
}
91+
92+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// ColletionAdapterCellData.swift
3+
// PatternsSwift
4+
//
5+
// Created by mrustaa on 01/05/2020.
6+
// Copyright © 2020 mrustaa. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class CollectionAdapterCellData: NSObject {
12+
13+
open func size() -> CGSize {
14+
return .zero
15+
}
16+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// ColletionAdapterItem.swift
3+
// PatternsSwift
4+
//
5+
// Created by mrustaa on 01/05/2020.
6+
// Copyright © 2020 mrustaa. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class CollectionAdapterItem: NSObject {
12+
13+
public let cellClass: AnyClass
14+
public let cellData: CollectionAdapterCellData?
15+
16+
public var cellReuseIdentifier: String {
17+
return String(describing: cellClass)
18+
}
19+
20+
init(cellClass: AnyClass, cellData: CollectionAdapterCellData? = nil) {
21+
self.cellClass = cellClass
22+
self.cellData = cellData
23+
}
24+
25+
public func size() -> CGSize {
26+
return cellData?.size() ?? .zero
27+
}
28+
29+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// CollectionAdapterTypes.swift
3+
// PatternsSwift
4+
//
5+
// Created by mrustaa on 01/05/2020.
6+
// Copyright © 2020 mrustaa. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
typealias CollectionAdapterCountCallback = () -> Int
12+
typealias CollectionAdapterCellIndexCallback = (_ index: Int) -> UICollectionViewCell
13+
typealias CollectionAdapterSizeIndexCallback = (_ index: Int) -> CGSize
14+
typealias CollectionAdapterSelectIndexCallback = (_ index: Int) -> ()
15+
typealias CollectionAdapterWillEndDraggingCallback = (_ velocity: CGPoint, _ targetContentOffset: UnsafeMutablePointer<CGPoint>) -> ()
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// CollectionAdapterView.swift
3+
// PatternsSwift
4+
//
5+
// Created by mrustaa on 01/05/2020.
6+
// Copyright © 2020 mrustaa. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class CollectionAdapterView: UICollectionView {
12+
13+
var countCallback: CollectionAdapterCountCallback?
14+
var cellIndexCallback: CollectionAdapterCellIndexCallback?
15+
var sizeIndexCallback: CollectionAdapterSizeIndexCallback?
16+
var selectIndexCallback: CollectionAdapterSelectIndexCallback?
17+
var didScrollCallback: TableAdapterDidScrollCallback?
18+
var willEndDraggingCallback: CollectionAdapterWillEndDraggingCallback?
19+
20+
21+
var items: [CollectionAdapterItem] = []
22+
23+
required init?(coder: NSCoder) {
24+
super.init(coder: coder)
25+
update()
26+
}
27+
28+
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
29+
super.init(frame: frame, collectionViewLayout: layout)
30+
update()
31+
}
32+
33+
func update() {
34+
delegate = self
35+
dataSource = self
36+
}
37+
38+
39+
public func set(items: [CollectionAdapterItem]) {
40+
items.forEach {
41+
registerNibIfNeeded(for: $0)
42+
}
43+
self.items = items
44+
reloadData()
45+
}
46+
47+
public func registerNibIfNeeded(for item: CollectionAdapterItem) {
48+
let nib = UINib(nibName: item.cellReuseIdentifier, bundle: nil)
49+
register(nib, forCellWithReuseIdentifier: item.cellReuseIdentifier)
50+
}
51+
52+
public func clear() {
53+
items = []
54+
reloadData()
55+
}
56+
57+
private func cellAt(_ indexPath: IndexPath) -> CollectionAdapterCell? {
58+
let item = items[indexPath.row]
59+
let cellIdentifier = item.cellReuseIdentifier
60+
let cell = dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? CollectionAdapterCell
61+
cell?.cellData = item.cellData
62+
return cell
63+
}
64+
65+
public func cell<T>(index: Int,
66+
completion: @escaping(T)->() ) {
67+
guard let cell = cellForItem(at: .init(row: index, section: 0)) as? T else {
68+
return
69+
}
70+
completion(cell)
71+
}
72+
73+
}
74+
75+
extension CollectionAdapterView: UICollectionViewDelegate {
76+
77+
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
78+
selectIndexCallback?(indexPath.row)
79+
}
80+
}
81+
82+
extension CollectionAdapterView: UICollectionViewDataSource {
83+
84+
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
85+
if !items.isEmpty {
86+
return items.count
87+
}
88+
if let countCallback = countCallback {
89+
return countCallback()
90+
}
91+
return 0
92+
}
93+
94+
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
95+
if !items.isEmpty {
96+
let item = items[indexPath.row]
97+
let cell = cellAt(indexPath)
98+
cell?.fill(data: item.cellData)
99+
return cell ?? UICollectionViewCell()
100+
}
101+
if let cellIndexCallback = cellIndexCallback {
102+
return cellIndexCallback(indexPath.row)
103+
}
104+
return UICollectionViewCell()
105+
}
106+
}
107+
108+
extension CollectionAdapterView: UICollectionViewDelegateFlowLayout {
109+
110+
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
111+
if !items.isEmpty {
112+
let item = items[indexPath.row]
113+
return item.size()
114+
}
115+
if let sizeIndexCallback = sizeIndexCallback {
116+
return sizeIndexCallback(indexPath.row)
117+
}
118+
return .zero
119+
}
120+
}
121+
122+
extension CollectionAdapterView: UIScrollViewDelegate {
123+
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
124+
didScrollCallback?()
125+
}
126+
127+
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
128+
willEndDraggingCallback?(velocity, targetContentOffset)
129+
}
130+
}
131+
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright (c) 2017 Cœur
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
// this software and associated documentation files (the "Software"), to deal in
5+
// the Software without restriction, including without limitation the rights to
6+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+
// the Software, and to permit persons to whom the Software is furnished to do so,
8+
// subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in all
11+
// copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19+
20+
import UIKit
21+
22+
/**
23+
* Simple UICollectionViewFlowLayout that centers the cells rather than justify them
24+
*
25+
* Based on https://github.com/Coeur/UICollectionViewLeftAlignedLayout
26+
*/
27+
open class UICollectionViewCenteredFlowLayout: UICollectionViewFlowLayout {
28+
open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
29+
guard let layoutAttributesForElements = super.layoutAttributesForElements(in: rect) else {
30+
return nil
31+
}
32+
guard let collectionView = collectionView else {
33+
return layoutAttributesForElements
34+
}
35+
// we group copies of the elements from the same row/column
36+
var representedElements: [UICollectionViewLayoutAttributes] = []
37+
var cells: [[UICollectionViewLayoutAttributes]] = [[]]
38+
var previousFrame: CGRect?
39+
if scrollDirection == .vertical {
40+
for layoutAttributes in layoutAttributesForElements {
41+
guard layoutAttributes.representedElementKind == nil else {
42+
representedElements.append(layoutAttributes)
43+
continue
44+
}
45+
// copying is required to avoid "UICollectionViewFlowLayout cache mismatched frame"
46+
let currentItemAttributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes
47+
// if the current frame, once stretched to the full row doesn't intersect the previous frame then they are on different rows
48+
if previousFrame != nil && !currentItemAttributes.frame.intersects(CGRect(x: -.greatestFiniteMagnitude, y: previousFrame!.origin.y, width: .infinity, height: previousFrame!.size.height)) {
49+
cells.append([])
50+
}
51+
cells[cells.endIndex - 1].append(currentItemAttributes)
52+
previousFrame = currentItemAttributes.frame
53+
}
54+
// we reposition all elements
55+
return representedElements + cells.flatMap { group -> [UICollectionViewLayoutAttributes] in
56+
guard let section = group.first?.indexPath.section else {
57+
return group
58+
}
59+
let evaluatedSectionInset = evaluatedSectionInsetForSection(at: section)
60+
let evaluatedMinimumInteritemSpacing = evaluatedMinimumInteritemSpacingForSection(at: section)
61+
var origin = (collectionView.bounds.width + evaluatedSectionInset.left - evaluatedSectionInset.right - group.reduce(0, { $0 + $1.frame.size.width }) - CGFloat(group.count - 1) * evaluatedMinimumInteritemSpacing) / 2
62+
// we reposition each element of a group
63+
return group.map {
64+
$0.frame.origin.x = origin
65+
origin += $0.frame.size.width + evaluatedMinimumInteritemSpacing
66+
return $0
67+
}
68+
}
69+
} else {
70+
for layoutAttributes in layoutAttributesForElements {
71+
guard layoutAttributes.representedElementKind == nil else {
72+
representedElements.append(layoutAttributes)
73+
continue
74+
}
75+
// copying is required to avoid "UICollectionViewFlowLayout cache mismatched frame"
76+
let currentItemAttributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes
77+
// if the current frame, once stretched to the full column doesn't intersect the previous frame then they are on different columns
78+
if previousFrame != nil && !currentItemAttributes.frame.intersects(CGRect(x: previousFrame!.origin.x, y: -.greatestFiniteMagnitude, width: previousFrame!.size.width, height: .infinity)) {
79+
cells.append([])
80+
}
81+
cells[cells.endIndex - 1].append(currentItemAttributes)
82+
previousFrame = currentItemAttributes.frame
83+
}
84+
// we reposition all elements
85+
return representedElements + cells.flatMap { group -> [UICollectionViewLayoutAttributes] in
86+
guard let section = group.first?.indexPath.section else {
87+
return group
88+
}
89+
let evaluatedSectionInset = evaluatedSectionInsetForSection(at: section)
90+
let evaluatedMinimumInteritemSpacing = evaluatedMinimumInteritemSpacingForSection(at: section)
91+
var origin = (collectionView.bounds.height + evaluatedSectionInset.top - evaluatedSectionInset.bottom - group.reduce(0, { $0 + $1.frame.size.height }) - CGFloat(group.count - 1) * evaluatedMinimumInteritemSpacing) / 2
92+
// we reposition each element of a group
93+
return group.map {
94+
$0.frame.origin.y = origin
95+
origin += $0.frame.size.height + evaluatedMinimumInteritemSpacing
96+
return $0
97+
}
98+
}
99+
}
100+
}
101+
}
102+
103+
extension UICollectionViewFlowLayout {
104+
internal func evaluatedSectionInsetForSection(at section: Int) -> UIEdgeInsets {
105+
return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, insetForSectionAt: section) ?? sectionInset
106+
}
107+
internal func evaluatedMinimumInteritemSpacingForSection(at section: Int) -> CGFloat {
108+
return (collectionView?.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView!, layout: self, minimumInteritemSpacingForSectionAt: section) ?? minimumInteritemSpacing
109+
}
110+
}

0 commit comments

Comments
 (0)