美文网首页
UIKit框架(五十二) —— 基于iOS14的UICollec

UIKit框架(五十二) —— 基于iOS14的UICollec

作者: 刀客传奇 | 来源:发表于2021-01-25 19:21 被阅读0次

    版本记录

    版本号 时间
    V1.0 2021.01.25 星期一

    前言

    iOS中有关视图控件用户能看到的都在UIKit框架里面,用户交互也是通过UIKit进行的。感兴趣的参考上面几篇文章。
    1. UIKit框架(一) —— UIKit动力学和移动效果(一)
    2. UIKit框架(二) —— UIKit动力学和移动效果(二)
    3. UIKit框架(三) —— UICollectionViewCell的扩张效果的实现(一)
    4. UIKit框架(四) —— UICollectionViewCell的扩张效果的实现(二)
    5. UIKit框架(五) —— 自定义控件:可重复使用的滑块(一)
    6. UIKit框架(六) —— 自定义控件:可重复使用的滑块(二)
    7. UIKit框架(七) —— 动态尺寸UITableViewCell的实现(一)
    8. UIKit框架(八) —— 动态尺寸UITableViewCell的实现(二)
    9. UIKit框架(九) —— UICollectionView的数据异步预加载(一)
    10. UIKit框架(十) —— UICollectionView的数据异步预加载(二)
    11. UIKit框架(十一) —— UICollectionView的重用、选择和重排序(一)
    12. UIKit框架(十二) —— UICollectionView的重用、选择和重排序(二)
    13. UIKit框架(十三) —— 如何创建自己的侧滑式面板导航(一)
    14. UIKit框架(十四) —— 如何创建自己的侧滑式面板导航(二)
    15. UIKit框架(十五) —— 基于自定义UICollectionViewLayout布局的简单示例(一)
    16. UIKit框架(十六) —— 基于自定义UICollectionViewLayout布局的简单示例(二)
    17. UIKit框架(十七) —— 基于自定义UICollectionViewLayout布局的简单示例(三)
    18. UIKit框架(十八) —— 基于CALayer属性的一种3D边栏动画的实现(一)
    19. UIKit框架(十九) —— 基于CALayer属性的一种3D边栏动画的实现(二)
    20. UIKit框架(二十) —— 基于UILabel跑马灯类似效果的实现(一)
    21. UIKit框架(二十一) —— UIStackView的使用(一)
    22. UIKit框架(二十二) —— 基于UIPresentationController的自定义viewController的转场和展示(一)
    23. UIKit框架(二十三) —— 基于UIPresentationController的自定义viewController的转场和展示(二)
    24. UIKit框架(二十四) —— 基于UICollectionViews和Drag-Drop在两个APP间的使用示例 (一)
    25. UIKit框架(二十五) —— 基于UICollectionViews和Drag-Drop在两个APP间的使用示例 (二)
    26. UIKit框架(二十六) —— UICollectionView的自定义布局 (一)
    27. UIKit框架(二十七) —— UICollectionView的自定义布局 (二)
    28. UIKit框架(二十八) —— 一个UISplitViewController的简单实用示例 (一)
    29. UIKit框架(二十九) —— 一个UISplitViewController的简单实用示例 (二)
    30. UIKit框架(三十) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的简单示例(一)
    31. UIKit框架(三十一) —— 基于UICollectionViewCompositionalLayout API的UICollectionViews布局的简单示例(二)
    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转盘效果的实现(一)
    39. UIKit框架(三十九) —— iOS 13中UISearchController 和 UISearchBar的新更改(一)
    40. UIKit框架(四十) —— iOS 13中UISearchController 和 UISearchBar的新更改(二)
    41. UIKit框架(四十一) —— 使用协议构建自定义Collection(一)
    42. UIKit框架(四十二) —— 使用协议构建自定义Collection(二)
    43. UIKit框架(四十三) —— CALayer的简单实用示例(一)
    44. UIKit框架(四十四) —— CALayer的简单实用示例(二)
    45. UIKit框架(四十五) —— 支持DarkMode的简单示例(一)
    46. UIKit框架(四十六) —— 支持DarkMode的简单示例(二)
    47. UIKit框架(四十七) —— 自定义Calendar Control的简单示例(一)
    48. UIKit框架(四十八) —— 自定义Calendar Control的简单示例(二)
    49. UIKit框架(四十九) —— UIVisualEffectView原理和简单使用(一)
    50. UIKit框架(五十) —— UIVisualEffectView原理和简单使用(二)
    51. UIKit框架(五十一) —— 基于iOS14的UICollectionView List的创建(一)

    源码

    1. Swift

    首先看下工程组织结构

    下面就是源码了

    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?
    }
    

    后记

    本篇主要讲述了基于iOS14UICollectionView List的创建,感兴趣的给个赞或者关注~~~

    相关文章

      网友评论

          本文标题:UIKit框架(五十二) —— 基于iOS14的UICollec

          本文链接:https://www.haomeiwen.com/subject/ocmizktx.html