版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2020.06.27 星期六 |
前言
iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面,用戶交互也是通過UIKit進(jìn)行的。感興趣的參考上面幾篇文章砾脑。
1. UIKit框架(一) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(一)
2. UIKit框架(二) —— UIKit動(dòng)力學(xué)和移動(dòng)效果(二)
3. UIKit框架(三) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(一)
4. UIKit框架(四) —— UICollectionViewCell的擴(kuò)張效果的實(shí)現(xiàn)(二)
5. UIKit框架(五) —— 自定義控件:可重復(fù)使用的滑塊(一)
6. UIKit框架(六) —— 自定義控件:可重復(fù)使用的滑塊(二)
7. UIKit框架(七) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(一)
8. UIKit框架(八) —— 動(dòng)態(tài)尺寸UITableViewCell的實(shí)現(xiàn)(二)
9. UIKit框架(九) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(一)
10. UIKit框架(十) —— UICollectionView的數(shù)據(jù)異步預(yù)加載(二)
11. UIKit框架(十一) —— UICollectionView的重用嫂冻、選擇和重排序(一)
12. UIKit框架(十二) —— UICollectionView的重用伊脓、選擇和重排序(二)
13. UIKit框架(十三) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(一)
14. UIKit框架(十四) —— 如何創(chuàng)建自己的側(cè)滑式面板導(dǎo)航(二)
15. UIKit框架(十五) —— 基于自定義UICollectionViewLayout布局的簡(jiǎn)單示例(一)
16. UIKit框架(十六) —— 基于自定義UICollectionViewLayout布局的簡(jiǎn)單示例(二)
17. UIKit框架(十七) —— 基于自定義UICollectionViewLayout布局的簡(jiǎn)單示例(三)
18. UIKit框架(十八) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫的實(shí)現(xiàn)(二)
20. UIKit框架(二十) —— 基于UILabel跑馬燈類似效果的實(shí)現(xiàn)(一)
21. UIKit框架(二十一) —— UIStackView的使用(一)
22. UIKit框架(二十二) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場(chǎng)和展示(一)
23. UIKit框架(二十三) —— 基于UIPresentationController的自定義viewController的轉(zhuǎn)場(chǎng)和展示(二)
24. UIKit框架(二十四) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (一)
25. UIKit框架(二十五) —— 基于UICollectionViews和Drag-Drop在兩個(gè)APP間的使用示例 (二)
26. UIKit框架(二十六) —— UICollectionView的自定義布局 (一)
27. UIKit框架(二十七) —— UICollectionView的自定義布局 (二)
28. UIKit框架(二十八) —— 一個(gè)UISplitViewController的簡(jiǎn)單實(shí)用示例 (一)
29. UIKit框架(二十九) —— 一個(gè)UISplitViewController的簡(jiǎn)單實(shí)用示例 (二)
30. UIKit框架(三十) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的簡(jiǎn)單示例(一)
31. UIKit框架(三十一) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的簡(jiǎn)單示例(二)
32. UIKit框架(三十二) —— 替換Peek and Pop交互的基于iOS13的Context Menus(一)
33. UIKit框架(三十三) —— 替換Peek and Pop交互的基于iOS13的Context Menus(二)
34. UIKit框架(三十四) —— Accessibility的使用(一)
35. UIKit框架(三十五) —— Accessibility的使用(二)
36. UIKit框架(三十六) —— UICollectionView UICollectionViewDiffableDataSource的使用(一)
37. UIKit框架(三十七) —— UICollectionView UICollectionViewDiffableDataSource的使用(二)
38. UIKit框架(三十八) —— 基于CollectionView轉(zhuǎn)盤效果的實(shí)現(xiàn)(一)
39. UIKit框架(三十九) —— iOS 13中UISearchController 和 UISearchBar的新更改(一)
40. UIKit框架(四十) —— iOS 13中UISearchController 和 UISearchBar的新更改(二)
41. UIKit框架(四十一) —— 使用協(xié)議構(gòu)建自定義Collection(一)
源碼
1. Swift
看下源碼
1. Bag.playground
struct Bag<Element: Hashable> {
fileprivate var contents: [Element: Int] = [:]
var uniqueCount: Int {
return contents.count
}
var totalCount: Int {
return contents.values.reduce(0) { $0 + $1 }
}
init() { }
init<S: Sequence>(_ sequence: S) where
S.Iterator.Element == Element {
for element in sequence {
add(element)
}
}
init<S: Sequence>(_ sequence: S) where
S.Iterator.Element == (key: Element, value: Int) {
for (element, count) in sequence {
add(element, occurrences: count)
}
}
mutating func add(_ member: Element, occurrences: Int = 1) {
precondition(occurrences > 0,
"Can only add a positive number of occurrences")
if let currentCount = contents[member] {
contents[member] = currentCount + occurrences
} else {
contents[member] = occurrences
}
}
mutating func remove(_ member: Element, occurrences: Int = 1) {
guard
let currentCount = contents[member],
currentCount >= occurrences
else {
return
}
precondition(occurrences > 0,
"Can only remove a positive number of occurrences")
if currentCount > occurrences {
contents[member] = currentCount - occurrences
} else {
contents.removeValue(forKey: member)
}
}
}
extension Bag: CustomStringConvertible {
var description: String {
return String(describing: contents)
}
}
extension Bag: ExpressibleByArrayLiteral {
init(arrayLiteral elements: Element...) {
self.init(elements)
}
}
extension Bag: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (Element, Int)...) {
self.init(elements.map { (key: $0.0, value: $0.1) })
}
}
extension Bag: Sequence {
typealias Iterator = AnyIterator<(element: Element, count: Int)>
func makeIterator() -> Iterator {
var iterator = contents.makeIterator()
return AnyIterator {
return iterator.next()
}
}
}
extension Bag: Collection {
// 1
typealias Index = BagIndex<Element>
var startIndex: Index {
// 2.1
return BagIndex(contents.startIndex)
}
var endIndex: Index {
// 2.2
return BagIndex(contents.endIndex)
}
subscript (position: Index) -> Iterator.Element {
precondition((startIndex ..< endIndex).contains(position),
"out of bounds")
// 3
let dictionaryElement = contents[position.index]
return (element: dictionaryElement.key,
count: dictionaryElement.value)
}
func index(after i: Index) -> Index {
// 4
return Index(contents.index(after: i.index))
}
}
struct BagIndex<Element: Hashable> {
fileprivate let index: DictionaryIndex<Element, Int>
fileprivate init(
_ dictionaryIndex: DictionaryIndex<Element, Int>) {
self.index = dictionaryIndex
}
}
extension BagIndex: Comparable {
static func == (lhs: BagIndex, rhs: BagIndex) -> Bool {
return lhs.index == rhs.index
}
static func < (lhs: BagIndex, rhs: BagIndex) -> Bool {
return lhs.index < rhs.index
}
}
var shoppingCart = Bag<String>()
shoppingCart.add("Banana")
shoppingCart.add("Orange", occurrences: 2)
shoppingCart.add("Banana")
shoppingCart.remove("Orange")
precondition("\(shoppingCart)" == "\(shoppingCart.contents)",
"Expected bag description to match its contents description")
let dataArray = ["Banana", "Orange", "Banana"]
let dataDictionary = ["Banana": 2, "Orange": 1]
let dataSet: Set = ["Banana", "Orange", "Banana"]
var arrayBag = Bag(dataArray)
precondition(arrayBag.contents == dataDictionary,
"Expected arrayBag contents to match \(dataDictionary)")
var dictionaryBag = Bag(dataDictionary)
precondition(dictionaryBag.contents == dataDictionary,
"Expected dictionaryBag contents to match \(dataDictionary)")
var setBag = Bag(dataSet)
precondition(setBag.contents == ["Banana": 1, "Orange": 1],
"Expected setBag contents to match \(["Banana": 1, "Orange": 1])")
var arrayLiteralBag: Bag = ["Banana", "Orange", "Banana"]
precondition(arrayLiteralBag.contents == dataDictionary,
"Expected arrayLiteralBag contents to match \(dataDictionary)")
var dictionaryLiteralBag: Bag = ["Banana": 2, "Orange": 1]
precondition(dictionaryLiteralBag.contents == dataDictionary,
"Expected dictionaryLiteralBag contents to match \(dataDictionary)")
for element in shoppingCart {
print(element)
}
for (element, count) in shoppingCart {
print("Element: \(element), Count: \(count)")
}
// Find all elements with a count greater than 1
let moreThanOne = shoppingCart.filter { $0.1 > 1 }
moreThanOne
precondition(
moreThanOne.first!.element == "Banana" && moreThanOne.first!.count == 2,
"Expected moreThanOne contents to be [(\"Banana\", 2)]")
// Get an array of all elements without counts
let itemList = shoppingCart.map { $0.0 }
itemList
precondition(
itemList == ["Orange", "Banana"] ||
itemList == ["Banana", "Orange"],
"Expected itemList contents to be [\"Orange\", \"Banana\"] or [\"Banana\", \"Orange\"]")
// Get the total number of items in the bag
let numberOfItems = shoppingCart.reduce(0) { $0 + $1.1 }
numberOfItems
precondition(numberOfItems == 3,
"Expected numberOfItems contents to be 3")
// Get a sorted array of elements by their count in decending order
let sorted = shoppingCart.sorted { $0.0 < $1.0 }
sorted
precondition(
sorted.first!.element == "Banana" && moreThanOne.first!.count == 2,
"Expected sorted contents to be [(\"Banana\", 2), (\"Orange\", 1)]")
// Get the first item in the bag
let firstItem = shoppingCart.first
precondition(
(firstItem!.element == "Orange" && firstItem!.count == 1) ||
(firstItem?.element == "Banana" && firstItem?.count == 2),
"Expected first item of shopping cart to be (\"Orange\", 1) or (\"Banana\", 2)")
// Check if the bag is empty
let isEmpty = shoppingCart.isEmpty
precondition(isEmpty == false,
"Expected shopping cart to not be empty")
// Get the number of unique items in the bag
let uniqueItems = shoppingCart.count
precondition(uniqueItems == 2,
"Expected shoppingCart to have 2 unique items")
// Find the first item with an element of "Banana"
let bananaIndex = shoppingCart.indices.first { shoppingCart[$0].element == "Banana" }!
let banana = shoppingCart[bananaIndex]
precondition(banana.element == "Banana" && banana.count == 2,
"Expected banana to have value (\"Banana\", 2)")
let fruitBasket = Bag(dictionaryLiteral:
("Apple", 5), ("Orange", 2), ("Pear", 3), ("Banana", 7))
let fruitSlice = fruitBasket.dropFirst()
if let fruitMinIndex = fruitSlice.indices.min(by:
{ fruitSlice[$0] > fruitSlice[$1] }) {
let basketElement = fruitBasket[fruitMinIndex]
let sliceElement = fruitSlice[fruitMinIndex]
precondition(basketElement == sliceElement,
"Expected basketElement and sliceElement to be the same element")
}
后記
本篇主要講述了使用協(xié)議構(gòu)建自定義Collection,感興趣的給個(gè)贊或者關(guān)注~~~