[SWIFT] Implémentez iOS14 UICollectionView avec CustomCell.

introduction

La dernière fois, j'ai écrit Article implémentant UICollectionView d'iOS14, donc il semble que la gestion des cellules personnalisées a changé, alors écrivons ceci dans l'article aussi! Je l'ai écrit en pensant cela, mais c'était difficile parce que le traitement a considérablement changé par rapport au passé. Je suis inquiet si c'est vrai, alors je me trompe ici, vous devriez écrire ceci! Veuillez commenter si vous en avez: persévérez:

Coin d'introduction de caractère de cellule personnalisé

Classe UICollectionViewListCell

C'est juste une classe de cellule. Je ne fais rien de particulier.

Classe UICellConfigurationState

Il garde l'état. ʻIsSelected et ʻisFocused sont fournis par défaut. Vous pouvez également personnaliser et ajouter. (Pas traité cette fois.)

Classe UIView

Créez une vue personnalisée.

Classe UIContentConfiguration

Une classe qui initialise une vue personnalisée, reçoit les données à afficher de la cellule et ʻUICellConfigurationState`, la reflète dans la vue personnalisée et renvoie la vue à la cellule. C'est le plus important. C'est le numéro 4.

Image de mise en œuvre

Mets délicieusement une étoile pour faire la différence par rapport à l'article précédent. ..

Tous les codes

Il y a 6 fichiers au total. SimpleCustomCell.storyboard SimpleCustomCellViewController.swift SimpleCustomCell.swift SimpleCustomCellConfiguration.swift SimpleCustomCellView.xib SimpleCustomCellView.swift

SimpleCustomCellViewController.swift

SimpleCustomCellViewController.swift


class SimpleCustomCellViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    enum Section: CaseIterable {
        case kanto
        case kyusyu
    }
    
    let data: [Section: [String]] = [
        .kanto: ["Kanto", "Tokyo", "Chiba"],
        .kyusyu: ["Kyusyu", "Fukuoka", "Miyazaki"]
    ]

    var collectionViewDataSource: UICollectionViewDiffableDataSource<Section, String>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var layoutConfig = UICollectionLayoutListConfiguration(appearance: .grouped)
        layoutConfig.headerMode = UICollectionLayoutListConfiguration.HeaderMode.firstItemInSection

        let layout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
        collectionView.collectionViewLayout = layout
        
        collectionViewDataSource = createDataSource()
        reloadList()
    }

    func createDataSource() -> UICollectionViewDiffableDataSource<Section, String> {
        
        let normalCell = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, text) in
            var content = cell.defaultContentConfiguration()
            content.text = text
            cell.contentConfiguration = content
        }
        
        let customCell = UICollectionView.CellRegistration<SimpleCustomCell, String> { (cell, indexPath, text) in
            cell.title = text
        }
        
        return UICollectionViewDiffableDataSource<Section, String>(collectionView: collectionView) {
            (collectionView, indexPath, text) -> UICollectionViewCell? in
            
            //Une cellule normale est utilisée pour le titre de la section.
            if indexPath.row == 0 {
                return collectionView.dequeueConfiguredReusableCell(using: normalCell, for: indexPath, item: text)
            } else {
                return collectionView.dequeueConfiguredReusableCell(using: customCell, for: indexPath, item: text)
            }
        }
    }
    
    func reloadList(){
        var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
        snapshot.appendSections(Section.allCases)
        snapshot.appendItems(data[.kanto]!, toSection: .kanto)
        snapshot.appendItems(data[.kyusyu]!, toSection: .kyusyu)
        collectionViewDataSource.apply(snapshot)
    }
}

Kaisetsu

C'est le seul endroit qui soit spécial. ʻLors de la configuration de UICollectionViewListCell, j'ai appelé la méthode defaultContentConfiguration pour définir le contenu, mais comme le processus est passé à SimpleCustomCell, je ne passe que title` ici.

let customCell = UICollectionView.CellRegistration<SimpleCustomCell, String> { (cell, indexPath, text) in
	cell.title = text
}

SimpleCustomCell.swift

SimpleCustomCell.swift


class SimpleCustomCell: UICollectionViewListCell {

    var title: String!

    override func updateConfiguration(using state: UICellConfigurationState) {
        var newConfiguration = SimpleCustomCellConfiguration()
        newConfiguration.title = title
        contentConfiguration = newConfiguration
    }
}

Kaisetsu

ʻUpdateConfiguration est une méthode qui est appelée lorsque les données sont ʻappliquer à la collectionView et lorsque la méthode setNeedsUpdateConfiguration est appelée et que la mise en page doit être mise à jour. Ici, la configuration est initialisée et les données (titre) sont compactées et définies dans le contentConfiguration de la cellule elle-même. (L'état de l'argument n'est pas utilisé car il ne gère pas l'état cette fois.)

SimpleCustomCellConfiguration.swift

SimpleCustomCellConfiguration.swift


struct SimpleCustomCellConfiguration: UIContentConfiguration, Hashable {

    var title: String?
    
    func makeContentView() -> UIView & UIContentView {
        return SimpleCustomCellView(configuration: self)
    }

    func updated(for state: UIConfigurationState) -> Self {
        return self
    }
}

Kaisetsu

La méthode makeContentView est une méthode qui crée une vue à afficher dans une cellule. Se passer à la vue comme argument. La méthode ʻupdated` est une méthode qui est appelée lorsque l'état change. Il n'est pas utilisé.

SimpleCustomCellView.xib(.swift)

SimpleCustomCellView.swift


class SimpleCustomCellView: UIView, UIContentView {
    
    @IBOutlet var nameLabel: UILabel!

    var configuration: UIContentConfiguration
    
    init(configuration: SimpleCustomCellConfiguration) {
        self.configuration = configuration
        super.init(frame: .zero)
        loadNib()
        setUpUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func loadNib() {
        let nib = UINib(nibName: "\(SimpleCustomCellView.self)", bundle: nil)
        guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else { return }
        view.frame = frame
        addSubview(view)
    }
    
    private func setUpUI() {
        guard let configuration = configuration as? SimpleCustomCellConfiguration else { return }
        nameLabel.text = configuration.title
    }
}

Kaisetsu

Je charge xib et définit les données de configuration passées sur Label. Il n'y a rien à expliquer en particulier.

Sommaire

Il semble que l'utilisation de Configuration la rend plus légère et plus facile à réutiliser. Par rapport à la méthode conventionnelle utilisant Delegate et DataSource, je ne savais pas où et quelle méthode était appelée, et je sentais que la sensation de boîte noire augmentait. Cela ne me dérangera-t-il pas une fois que je m'y serai habitué? ..

Ensuite, j'écrirai un article en utilisant l'état que je n'ai pas utilisé cette fois. S'il vous plaît LGTM si vous le souhaitez car il sera chauve \ (^ o ^) /

Cliquez ici pour git! https://github.com/ymarui/iOS14_UICollectionView_sample

Références

https://qiita.com/shiz/items/4227accc7d13ae439d1d#推奨される使用方法 https://swiftsenpai.com/development/collectionview-expandable-list-part2/

Recommended Posts

Implémentez iOS14 UICollectionView avec CustomCell.
Implémentez iOS14 UICollectionView avec le code minimum requis.
Pourquoi implémenter avec singleton au lieu de la méthode statique
Implémenter GraphQL avec Spring Boot
Implémentation de XLPagerTabStrip avec TabBarController
reload jCaptcha implémenté avec ajax