版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2021.01.25 星期一 |
前言
iOS中有關(guān)視圖控件用戶能看到的都在UIKit框架里面下梢,用戶交互也是通過(guò)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)畫(huà)的實(shí)現(xiàn)(一)
19. UIKit框架(十九) —— 基于CALayer屬性的一種3D邊欄動(dòng)畫(huà)的實(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(一)
42. UIKit框架(四十二) —— 使用協(xié)議構(gòu)建自定義Collection(二)
43. UIKit框架(四十三) —— CALayer的簡(jiǎn)單實(shí)用示例(一)
44. UIKit框架(四十四) —— CALayer的簡(jiǎn)單實(shí)用示例(二)
45. UIKit框架(四十五) —— 支持DarkMode的簡(jiǎn)單示例(一)
46. UIKit框架(四十六) —— 支持DarkMode的簡(jiǎn)單示例(二)
47. UIKit框架(四十七) —— 自定義Calendar Control的簡(jiǎn)單示例(一)
48. UIKit框架(四十八) —— 自定義Calendar Control的簡(jiǎn)單示例(二)
49. UIKit框架(四十九) —— UIVisualEffectView原理和簡(jiǎn)單使用(一)
50. UIKit框架(五十) —— UIVisualEffectView原理和簡(jiǎn)單使用(二)
51. UIKit框架(五十一) —— 基于iOS14的UICollectionView List的創(chuàng)建(一)
源碼
1. Swift
首先看下工程組織結(jié)構(gòu)
下面就是源碼了
1. Pet.swift
import Foundation
struct Pet: Hashable {
enum Category: CaseIterable, CustomStringConvertible {
case birds, cats, chameleons, cows, dogs, monkeys, penguins, pigs, rats, snakes, squirrels
}
let imageName: String
let name: String
let birthYear: Int
var age: Int {
let thisYear = Calendar.current.component(.year, from: Date())
return thisYear - birthYear
}
let category: Category
private let id = UUID()
}
extension Pet.Category {
var description: String {
switch self {
case .birds: return "Birds"
case .cats: return "Cats"
case .chameleons: return "Chameleons"
case .cows: return "Cows"
case .dogs: return "Dogs"
case .monkeys: return "Monkeys"
case .penguins: return "Penguins"
case .pigs: return "Pigs"
case .rats: return "Rats"
case .snakes: return "Snakes"
case .squirrels: return "Squirrels"
}
}
var pets: [Pet] {
switch self {
case .birds:
return [
Pet(imageName: "bird1", name: "Happy", birthYear: 2017, category: self),
Pet(imageName: "bird2", name: "Swifty", birthYear: 2018, category: self),
Pet(imageName: "bird3", name: "Speedy", birthYear: 2018, category: self)
]
case .cats:
return [
Pet(imageName: "cat1", name: "Max", birthYear: 2015, category: self),
Pet(imageName: "cat2", name: "Jake", birthYear: 2018, category: self),
Pet(imageName: "cat3", name: "Daisy", birthYear: 2012, category: self),
Pet(imageName: "cat4", name: "Sunny", birthYear: 2008, category: self),
Pet(imageName: "cat5", name: "Oscar", birthYear: 2017, category: self)
]
case .chameleons:
return [
Pet(imageName: "chameleon1", name: "Zoe", birthYear: 2015, category: self)
]
case .cows:
return [
Pet(imageName: "cow1", name: "Betty", birthYear: 2016, category: self),
Pet(imageName: "cow2", name: "Rosie", birthYear: 2013, category: self)
]
case .dogs:
return [
Pet(imageName: "dog1", name: "Buddy", birthYear: 2018, category: self),
Pet(imageName: "dog2", name: "Molly", birthYear: 2014, category: self),
Pet(imageName: "dog3", name: "Bella", birthYear: 2009, category: self),
Pet(imageName: "dog4", name: "Dixie", birthYear: 2018, category: self),
Pet(imageName: "dog5", name: "Freddy", birthYear: 2012, category: self),
Pet(imageName: "dog6", name: "Lucky", birthYear: 2016, category: self),
Pet(imageName: "dog7", name: "Snoopy", birthYear: 2015, category: self),
Pet(imageName: "dog8", name: "Joker", birthYear: 2018, category: self),
Pet(imageName: "dog9", name: "Diego", birthYear: 2018, category: self),
Pet(imageName: "dog10", name: "Bruno", birthYear: 2016, category: self)
]
case .monkeys:
return [
Pet(imageName: "monkey1", name: "Turbo", birthYear: 2015, category: self)
]
case .penguins:
return [
Pet(imageName: "penguin1", name: "Helen", birthYear: 2017, category: self),
Pet(imageName: "penguin2", name: "Fred", birthYear: 2014, category: self)
]
case .pigs:
return [
Pet(imageName: "pig1", name: "Piggy", birthYear: 2015, category: self)
]
case .rats:
return [
Pet(imageName: "rat1", name: "Cutie", birthYear: 2018, category: self)
]
case .snakes:
return [
Pet(imageName: "snake1", name: "Worm", birthYear: 2013, category: self),
Pet(imageName: "snake2", name: "Noodles", birthYear: 2018, category: self),
Pet(imageName: "snake3", name: "Slider", birthYear: 2017, category: self)
]
case .squirrels:
return [
Pet(imageName: "squirrel1", name: "Chippy", birthYear: 2017, category: self)
]
}
}
}
2. Item.swift
import Foundation
struct Item: Hashable {
let title: String
let pet: Pet?
private let id = UUID()
init(pet: Pet? = nil, title: String) {
self.pet = pet
self.title = title
}
}
3. PetExplorerViewController.swift
import UIKit
class PetExplorerViewController: UICollectionViewController {
// MARK: - Properties
lazy var dataSource = makeDataSource()
var adoptions = Set<Pet>()
// MARK: - Types
enum Section: Int, CaseIterable, Hashable {
case availablePets
case adoptedPets
}
typealias DataSource = UICollectionViewDiffableDataSource<Section, Item>
// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Pet Explorer"
configureLayout()
applyInitialSnapshots()
}
// MARK: - Functions
func configureLayout() {
let provider = {(_: Int, layoutEnv: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let configuration = UICollectionLayoutListConfiguration(appearance: .grouped)
return .list(using: configuration, layoutEnvironment: layoutEnv)
}
collectionView.collectionViewLayout = UICollectionViewCompositionalLayout(sectionProvider: provider)
}
func makeDataSource() -> DataSource {
return DataSource(collectionView: collectionView) { collectionView, indexPath, item -> UICollectionViewCell? in
if item.pet != nil {
guard let section = Section(rawValue: indexPath.section) else {
return nil
}
switch section {
case .availablePets:
return collectionView.dequeueConfiguredReusableCell(
using: self.petCellRegistration(), for: indexPath, item: item)
case .adoptedPets:
return collectionView.dequeueConfiguredReusableCell(
using: self.adoptedPetCellRegistration(), for: indexPath, item: item)
}
} else {
return collectionView.dequeueConfiguredReusableCell(
using: self.categoryCellregistration(), for: indexPath, item: item)
}
}
}
func applyInitialSnapshots() {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(Section.allCases)
dataSource.apply(snapshot, animatingDifferences: false)
var categorySnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
for category in Pet.Category.allCases {
let categoryItem = Item(title: String(describing: category))
categorySnapshot.append([categoryItem])
let petItems = category.pets.map { Item(pet: $0, title: $0.name) }
categorySnapshot.append(petItems, to: categoryItem)
}
dataSource.apply(categorySnapshot, to: .availablePets, animatingDifferences: false)
}
func updateDataSource(for pet: Pet) {
var snapshot = dataSource.snapshot()
let items = snapshot.itemIdentifiers
let petItem = items.first { item in
item.pet == pet
}
if let petItem = petItem {
snapshot.reloadItems([petItem])
dataSource.apply(snapshot, animatingDifferences: true, completion: nil)
}
}
}
// MARK: - CollectionView Cells
extension PetExplorerViewController {
func categoryCellregistration() -> UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
return .init { cell, _, item in
var configuration = cell.defaultContentConfiguration()
configuration.text = item.title
cell.contentConfiguration = configuration
let options = UICellAccessory.OutlineDisclosureOptions(style: .header)
let disclosureAccessory = UICellAccessory.outlineDisclosure(options: options)
cell.accessories = [disclosureAccessory]
}
}
func petCellRegistration() -> UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
return .init { cell, _, item in
guard let pet = item.pet else {
return
}
var configuration = cell.defaultContentConfiguration()
configuration.text = pet.name
configuration.secondaryText = "\(pet.age) years old"
configuration.image = UIImage(named: pet.imageName)
configuration.imageProperties.maximumSize = CGSize(width: 40, height: 40)
cell.contentConfiguration = configuration
cell.accessories = [UICellAccessory.disclosureIndicator()]
if self.adoptions.contains(pet) {
var backgroundConfig = UIBackgroundConfiguration.listPlainCell()
backgroundConfig.backgroundColor = .systemBlue
backgroundConfig.cornerRadius = 5
backgroundConfig.backgroundInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
cell.backgroundConfiguration = backgroundConfig
}
cell.contentConfiguration = configuration
cell.accessories = [UICellAccessory.disclosureIndicator()]
}
}
func adoptedPetCellRegistration() -> UICollectionView.CellRegistration<UICollectionViewListCell, Item> {
return .init { cell, _, item in
guard let pet = item.pet else {
return
}
var configuration = cell.defaultContentConfiguration()
configuration.text = "Your pet: \(pet.name)"
configuration.secondaryText = "\(pet.age) years old"
configuration.image = UIImage(named: pet.imageName)
configuration.imageProperties.maximumSize = CGSize(width: 40, height: 40)
cell.contentConfiguration = configuration
cell.accessories = [.disclosureIndicator()]
}
}
}
// MARK: - UICollectionViewDelegate
extension PetExplorerViewController {
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let item = dataSource.itemIdentifier(for: indexPath) else {
collectionView.deselectItem(at: indexPath, animated: true)
return
}
guard let pet = item.pet else {
return
}
pushDetailForPet(pet, withAdoptionStatus: adoptions.contains(pet))
}
func pushDetailForPet(_ pet: Pet, withAdoptionStatus isAdopted: Bool) {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let petDetailViewController =
storyboard.instantiateViewController(identifier: "PetDetailViewController") { coder in
return PetDetailViewController(coder: coder, pet: pet)
}
petDetailViewController.delegate = self
petDetailViewController.isAdopted = isAdopted
navigationController?.pushViewController(petDetailViewController, animated: true)
}
}
// MARK: - PetDetailViewControllerDelegate
extension PetExplorerViewController: PetDetailViewControllerDelegate {
func petDetailViewController(_ petDetailViewController: PetDetailViewController, didAdoptPet pet: Pet) {
adoptions.insert(pet)
var adoptedPetsSnapshot = dataSource.snapshot(for: .adoptedPets)
let newItem = Item(pet: pet, title: pet.name)
adoptedPetsSnapshot.append([newItem])
dataSource.apply(adoptedPetsSnapshot, to: .adoptedPets, animatingDifferences: true, completion: nil)
updateDataSource(for: pet)
}
}
4. PetDetailViewController.swift
import UIKit
protocol PetDetailViewControllerDelegate: class {
func petDetailViewController(_ petDetailViewController: PetDetailViewController, didAdoptPet pet: Pet)
}
class PetDetailViewController: UIViewController {
// MARK: - Properties
var pet: Pet
var isAdopted = false
weak var delegate: PetDetailViewControllerDelegate?
// MARK: - IBOutlets
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var name: UILabel!
@IBOutlet weak var age: UILabel!
@IBOutlet weak var adoptButton: UIButton!
// MARK: - Life Cycle
init?(coder: NSCoder, pet: Pet) {
self.pet = pet
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
adoptButton.setTitle("Adopt", for: .normal)
adoptButton.isHidden = isAdopted
imageView.image = UIImage(named: pet.imageName)
name.text = isAdopted ? "Your pet: \(pet.name)" : pet.name
age.text = "\(pet.age) years old"
}
}
// MARK: - IBActions
extension PetDetailViewController {
@IBAction func didTapAdoptButton(_ sender: UIButton) {
delegate?.petDetailViewController(self, didAdoptPet: pet)
navigationController?.popViewController(animated: true)
}
}
5. AppDelegate.swift
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { }
6. SceneDelegate.swift
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
}
后記
本篇主要講述了基于
iOS14
的UICollectionView List
的創(chuàng)建,感興趣的給個(gè)贊或者關(guān)注~~~