[Swift] J'ai essayé d'implémenter une interface utilisateur semblable à un profil Instagram avec UICollectionView avec juste du code sans storyboard

introduction

Cette fois, j'essaierai d'implémenter une interface utilisateur de type profil Instagram avec UICollectionView avec juste du code. Est le contenu

J'espère que cet article aide quelqu'un

C'est juste un débutant Swift qui a imité l'interface utilisateur, donc je pense qu'il y a des points qui ne peuvent pas être atteints. Si vous remarquez des erreurs dans la rédaction du code, veuillez nous donner quelques conseils! !!

Trois mois avant de commencer à écrire, Piempaon ne s'arrête pas

Formulaire rempli

last_qiita.gif

[Instagrammer qui aspire vraiment aux entrepreneurs]

Public cible

・ Débutants du développement d'applications iOS ・ Ceux qui veulent savoir comment utiliser UICollectionView ・ Ceux qui veulent se développer sans utiliser StoryBoard ・ Ceux qui aiment l'interface utilisateur d'Instagram

Environnement de développement

・ Version 11.3 (11C29) ・ Swift 5

Version terminée Github

Je mettrai le code source ci-dessous

https://github.com/Isseymiyamoto/FamousAppUI/tree/master/Instagram_profile/Instagram_profile

organisation des fichiers

Cette fois, nous ajouterons de nouveaux fichiers dans les dossiers View et Controller car nous n'effectuerons pas de communication telle que l'acquisition de données. Utils> Extensions.swift inclut des fonctions pour simplifier le traitement lié à la mise en page, Je n'entrerai pas dans les détails dans cet article, il serait donc utile que vous puissiez le copier à partir de Github.

スクリーンショット 2020-09-17 15.46.20.png

Passons maintenant à la mise en œuvre

Procédure de mise en œuvre

Pour 1 et 2, passez si vous n'avez pas besoin de TabBar

  1. Créez un fichier de contrôleur à utiliser
  2. Utilisez UITabBarController pour déterminer le contrôleur à afficher en tant que TabBar
  3. Dans SceneDelegate.swift, déterminez le contrôleur à afficher au démarrage
  4. Créez ProfileHeaderCell dans le dossier View
  5. Créer FilterView dans le dossier View
  6. Créez une PostCell pour afficher les photos publiées dans le dossier Afficher
  7. Combiné et terminé! !!

1. Créez un fichier Controller à utiliser

Ici, créons un fichier Controller pour travailler avec TabBar implémenté dans 2. Il y a 5 icônes d'onglet à afficher sur Instagram, alors créez 5 fichiers directement sous le dossier Controller.

ProfileController.swift


import UIKit

class ProfileController: UICollectionViewController{

  override func viewDidLoad() {
    super.viewDidLoad()

  }

}

Pour les 4 autres fichiers, ce qui suit est très bien

FeedController.swift



import UIKit

class FeedController: UIViewController{

  override func viewDidLoad() {
    super.viewDidLoad()

    //Entrez la chaîne de caractères que vous souhaitez afficher dans la barre de navigation
    navigation.item = "Publier"
  }

}

2. Utilisez UITabBarController pour déterminer le contrôleur à afficher en tant que TabBar

Créez MainTabController.swift directement sous le dossier controller afin de lier le fichier créé en 1 avec TabBar.

MainTabController.swift



import UIKit

class MainTabController: UITabBarController{
    
    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureUI()
        configureViewControllers()
    }
        
    // MARK: - Helpers
    
    func configureUI(){
        view.backgroundColor = .white
        tabBar.tintColor = .black
    }
    
    func configureViewControllers(){
        
        let feed = FeedController()
        let nav1 = templateNavigationController(image: UIImage(systemName: "house"), rootViewController: feed)
        
        let search = SearchController()
        let nav2 = templateNavigationController(image: UIImage(systemName: "magnifyingglass"), rootViewController: search)
        
        let upload = UploadPostController()
        let nav3 = templateNavigationController(image: UIImage(systemName: "plus.app"), rootViewController: upload)
        
        let notification = NotificationController()
        let nav4 = templateNavigationController(image: UIImage(systemName: "heart"), rootViewController: notification)
        //S'affiche comme si 2 notifications avaient été reçues
        nav4.tabBarItem.selectedImage = UIImage(systemName: "heart.fill")
        nav4.tabBarItem.badgeValue = "2"
        
        let profile = ProfileController(collectionViewLayout: UICollectionViewFlowLayout())
        let nav5 = templateNavigationController(image: UIImage(systemName: "person"), rootViewController: profile)
        
        //Décidez quel contrôleur placer sur la barre d'onglets
        viewControllers = [nav1, nav2, nav3, nav4, nav5]
        
        //Affichage initial du profileController
        selectedIndex = 4
    }
    
    //Tout rootViewController, fonction pour définir l'image tabIcon,Utilisé dans configureViewControllers
    func templateNavigationController(image: UIImage?, rootViewController: UIViewController) -> UINavigationController{
        let nav = UINavigationController(rootViewController: rootViewController)
        nav.tabBarItem.image = image
        nav.navigationBar.tintColor = .white
        return nav
    }
}

3. Dans SceneDelegate.swift, déterminez le contrôleur à afficher au démarrage

Maintenant, éditons SceneDelegate.swift et définissons MainTabController pour être affiché au démarrage.

SceneDelegate.swift



class SceneDelegate: UIResponder, UIWindowSceneDelegate {

  //réduction
  
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let scene = scene as? UIWindowScene else { return }
        window = UIWindow(windowScene: scene)
        window?.rootViewController = MainTabController()
        window?.makeKeyAndVisible()
    }

  //réduction
}

Lorsque vous démarrez Simulator après avoir défini ici, il est parfait si ce qui suit est affiché スクリーンショット 2020-09-28 20.04.35.png

4. Créez ProfileHeaderCell dans le dossier View

Ensuite, créons une vue à appliquer à ProfileController Je vais le faire dans le format suivant, mais commençons par créer un ProfileHeaderCell de la partie contour du profil ici

スクリーンショット 2020-09-28 20.17.06.png

Créez un fichier de ProfileHeader.swift directement sous Affichage

ProfileHeader.swift


import UIKit

//Ça ne doit pas être parce que c'est un haribote
protocol ProfileHeaderDelegate: class {
    func handleEditProfile(_ header: ProfileHeader)
}

class ProfileHeader: UICollectionViewCell{
    
    // MARK: - Properties
    
    //Ça ne doit pas être parce que c'est un haribote
    weak var delegate: ProfileHeaderDelegate?
    
    private let profileImageView: UIImageView = {
        let iv = UIImageView()
        iv.contentMode = .scaleAspectFit
        iv.clipsToBounds = true
        iv.image = UIImage(named: "Veuillez insérer une photo de manière appropriée")
        iv.layer.borderColor = UIColor.black.cgColor
        return iv
    }()
    
    private lazy var postCountButton = makeStatsButton(withNumber: "12")
    private lazy var followingCountButton = makeStatsButton(withNumber: "320")
    private lazy var followerCountButton = makeStatsButton(withNumber: "1000")
    
    private lazy var postCountLabel = makeStatsTitle(withTitle: "Publier")
    private lazy var followingCountLabel = makeStatsTitle(withTitle: "Suivant")
    private lazy var followerCountLabel = makeStatsTitle(withTitle: "Disciple")
    
    private let fullnameLabel: UILabel = {
        let label = UILabel()
        label.text = "Onamae"
        label.font = UIFont.boldSystemFont(ofSize: 14)
        return label
    }()
    
    private let bioLabel: UILabel = {
        let label = UILabel()
        label.text = "Il s'agit d'une tentative d'imiter l'interface utilisateur du profil Instagram. C'est vrai. Il imite juste."
        label.font = UIFont.systemFont(ofSize: 14)
        label.numberOfLines = 3
        return label
    }()
    
    private let editProfileButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Editer le profil", for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.addTarget(self, action: #selector(handleEditProfileButtonTapped), for: .touchUpInside)
        button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
        button.layer.borderColor = UIColor.lightGray.cgColor
        button.layer.borderWidth = 1
        button.layer.cornerRadius = 4
        button.backgroundColor = .white
        return button
    }()
    
    private let storiesPlusButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(UIImage(systemName: "plus"), for: .normal)
        button.tintColor = .black
        button.backgroundColor = .clear
        button.layer.borderColor = UIColor.lightGray.cgColor
        button.layer.borderWidth = 0.75
        return button
    }()
    
    private let storiesPlusLabel: UILabel = {
        let label = UILabel()
        label.text = "Nouveau"
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 10)
        return label
    }()
    
    // MARK: - Lifecycle
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        backgroundColor = .systemGroupedBackground
        
        let postCountStack = makeStatsStackView(button: postCountButton, label: postCountLabel)
        let followingCountStack = makeStatsStackView(button: followingCountButton, label: followingCountLabel)
        let followerCountStack = makeStatsStackView(button: followerCountButton, label: followerCountLabel)
        
        let infoStack = UIStackView(arrangedSubviews: [postCountStack, followingCountStack, followerCountStack])
        infoStack.axis = .horizontal
        infoStack.alignment = .center
        infoStack.distribution = .fillEqually
        
        addSubview(profileImageView)
        profileImageView.anchor(top: safeAreaLayoutGuide.topAnchor, left: leftAnchor, paddingTop: 16, paddingLeft: 16)
        profileImageView.setDimensions(width: 96, height: 96)
        profileImageView.layer.cornerRadius = 96 / 2
        
        addSubview(infoStack)
        infoStack.centerY(inView: profileImageView)
        infoStack.anchor(left: profileImageView.rightAnchor, right: rightAnchor, paddingLeft: 16, paddingRight: 32)
        
        addSubview(fullnameLabel)
        fullnameLabel.anchor(top: profileImageView.bottomAnchor, left: leftAnchor, right: rightAnchor, paddingTop: 16, paddingLeft: 16, paddingRight: 16)
        
        addSubview(bioLabel)
        bioLabel.anchor(top: fullnameLabel.bottomAnchor, left: leftAnchor, right: rightAnchor, paddingTop: 4, paddingLeft: 16, paddingRight: 16)
        
        addSubview(editProfileButton)
        editProfileButton.anchor(top: bioLabel.bottomAnchor, left: leftAnchor, right: rightAnchor, paddingTop: 16, paddingLeft: 16, paddingRight: 16 )
        
        addSubview(storiesPlusButton)
        storiesPlusButton.anchor(top: editProfileButton.bottomAnchor, left: leftAnchor, paddingTop: 16, paddingLeft: 16)
        storiesPlusButton.setDimensions(width: 64, height: 64)
        storiesPlusButton.layer.cornerRadius = 64 / 2
        
        addSubview(storiesPlusLabel)
        storiesPlusLabel.centerX(inView: storiesPlusButton)
        storiesPlusLabel.anchor(top: storiesPlusButton.bottomAnchor, paddingTop: 4)
    }
    
    
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - Selectors
    
    //Ça ne doit pas être parce que c'est un haribote
    @objc func handleEditProfileButtonTapped(){
        delegate?.handleEditProfile(self)
    }
    
    
    // MARK: - Helpers
    
    //Pour créer un StackView qui aligne le nombre de boutons et de détails verticalement
    fileprivate func makeStatsStackView(button: UIButton, label: UILabel) -> UIStackView{
        let stack = UIStackView(arrangedSubviews: [button, label])
        stack.axis = .vertical
        stack.alignment = .center
        stack.setDimensions(width: 160, height: 40)
        return stack
    }
    
    //Pour créer des boutons d'affichage tels que le nombre de publications et d'abonnés
    private func makeStatsButton(withNumber number: String) -> UIButton{
        let button = UIButton(type: .system)
        button.setTitle(number, for: .normal)
        button.setTitleColor(.black, for: .normal)
        button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
        return button
    }
    //Pour créer des étiquettes pour afficher des détails tels que le nombre de publications et d'abonnés
    private func makeStatsTitle(withTitle title: String) -> UILabel{
        let label = UILabel()
        label.text = title
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 14)
        return label
    }
}

Appliquons ceci au contrôleur de profil (sautez-le une fois en 5 et 6)

ProfileController.swift


import UIKit

private let profileHeaderCell = "ProfileHeaderCell"

class ProfileController: UICollectionViewController{
    
    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureUI()
    }
    
    // MARK: - Selectors
    
    //Ornement
    @objc func handleRightButtonTapped(){
        print("DEBUG: you pressed the button..")
    }
    
    @objc func handleRefresh(){
        //Ne rien faire car il n'y a pas de données
        collectionView.refreshControl?.beginRefreshing()
        collectionView.refreshControl?.endRefreshing()
    }
    
    // MARK: - Helpers
    
    //Paramètres de toute l'interface utilisateur
    func configureUI(){
        view.backgroundColor = .systemGroupedBackground
        
        configureNavigationBar()
        configureCollectionView()
        
        //Balayez vers le bas pour recharger les paramètres de vent
        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
        collectionView.refreshControl = refreshControl
    }
    
    //Paramètres liés à la navigationBar
    func configureNavigationBar(){
        navigationController?.navigationBar.tintColor = .black
        navigationController?.navigationBar.barTintColor = .systemGroupedBackground
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.shadowImage = UIImage()
        
        navigationItem.title = "user_id"
        navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "line.horizontal.3"), style: .plain, target: self, action: #selector(handleRightButtonTapped))
    }
    
    func configureCollectionView(){
        collectionView.backgroundColor = .systemGroupedBackground
        
        //Enregistrement d'en-tête de profil
        collectionView.register(ProfileHeader.self, forCellWithReuseIdentifier: profileHeaderCell)
        
        //Placer collectionView de manière à ne pas couvrir tabBar
        guard let tabHeight = tabBarController?.tabBar.frame.height else { return }
        collectionView.contentInset.bottom = tabHeight
    }
}

// MARK: - UICollectionViewDataSource / UICollectionViewDelegate

extension ProfileController{
    
    //Réglez le nombre de sections sur 1 pour le moment → Passez à 2 après avoir réglé PostCell
    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    //Nombre de cellules à afficher dans la section → Un seul en-tête de profil est requis, donc une fois
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }
    
    //Réglage de la cellule à afficher
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: profileHeaderCell, for: indexPath) as! ProfileHeader
        return cell
    }
}

// MARK: - UICollectionViewDelegateFlowLayout

extension ProfileController: UICollectionViewDelegateFlowLayout{
    
    //Réglage de la taille de la cellule → Veuillez modifier la hauteur de manière appropriée
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        return CGSize(width: view.frame.width, height: 340)
    }
}

Si vous démarrez le simulateur jusqu'à présent, la partie En-tête de profil sera affichée! Peut être! Finissons d'ici à la fin rapidement

5. Créer FilterView dans le dossier View

FilterView est une partie de filtre pour afficher votre propre liste de messages ou une liste marquée par vos amis. Sur ProfileController, il est affiché sous forme d'en-tête avec indexPath.section = 1

Maintenant, pour FilterView, créez-le en installant UICollectionView dans UICollectionReusableView. Oui, c'est-à-dire que le FilterViewCell de UICollectionViewCell est également créé dans un fichier séparé. faisons de notre mieux

ProfileFilterView.swift


import UIKit

private let profileHeaderCellIdentifier = "profileHeaderCell"

//Haribote
protocol ProfileFilterViewDelegate: class {
    func filterView(_ view: ProfileFilterView, didSelect index: Int)
}

class ProfileFilterView: UICollectionReusableView {
    
    // MARK: - Properties
    
    //Haribote
    weak var delegate: ProfileFilterViewDelegate?
    
    //collectionVoir à mettre en évidence
    lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .systemGroupedBackground
        cv.delegate = self
        cv.dataSource = self
        return cv
    }()
    
    //Animez ce gars pour créer un sentiment bien choisi
    private let underlineView: UIView = {
        let view = UIView()
        view.backgroundColor = .black
        return view
    }()
    
    //Borderline avec profileHeaderCell
    private let abovelineView: UIView = {
        let view = UIView()
        view.backgroundColor = .lightGray
        return view
    }()
    
    // MARK: - Lifecycle
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        collectionView.register(ProfileFilterCell.self, forCellWithReuseIdentifier: identifier)
        
        //IsSelected à l'initialisation=Déterminez quelle cellule est vraie
        let selectedIndexPath = IndexPath(row: 0, section: 0)
        collectionView.selectItem(at: selectedIndexPath, animated: true, scrollPosition: .left)
        
        addSubview(collectionView)
        //Développez la vue de collection pour remplir la vue parent
        collectionView.addConstraintsToFillView(self)
    }
    
    override func layoutSubviews() {
        addSubview(abovelineView)
        abovelineView.anchor(left: leftAnchor, bottom: topAnchor, width: frame.width, height: 0.5)
        
        addSubview(underlineView)
        underlineView.anchor(left: leftAnchor, bottom: bottomAnchor, width: frame.width / 2, height: 1)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: - UICollectionViewDataSource

extension ProfileFilterView: UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        //Puisqu'il y a deux choix de balise ou de message, le retour 2 est ok
        return ProfileFilterOptions.allCases.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ProfileFilterCell
        
        //Option de mise à jour côté cellule
        let option = ProfileFilterOptions(rawValue: indexPath.row)
        cell.option = option
        
        return cell
    }
}

// MARK: - UICollectionViewDelegate

extension ProfileFilterView: UICollectionViewDelegate{
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let cell = collectionView.cellForItem(at: indexPath)
        //0 à la coordonnée x de la cellule touchUpInside the underlineView.Bougez en 3 secondes
        let xPosition = cell?.frame.origin.x ?? 0
        
        UIView.animate(withDuration: 0.3) {
            self.underlineView.frame.origin.x = xPosition
        }
        
        //Haribote → Traitez et écrivez à l'origine pour que l'image d'affichage puisse être modifiée avec ProfileController
        delegate?.filterView(self, didSelect: indexPath.row)
    }
}

// MARK: - UICollectionViewDelegateFlowLayout

extension ProfileFilterView: UICollectionViewDelegateFlowLayout{
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let count = CGFloat(ProfileFilterOptions.allCases.count)
        return CGSize(width: frame.width / count, height: frame.height)
    }
    
    //Installé de manière à ce qu'il n'y ait aucun espace entre les éléments
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
}

ProfileFilterViewCell.swift


import UIKit

//Articles ou balisage Liste des articles Déterminez lequel
enum ProfileFilterOptions: Int, CaseIterable{
    case post
    case tag
    
    var systemImage: UIImage? {
        switch self {
        case .post: return UIImage(systemName: "rectangle.split.3x3")
        case .tag: return UIImage(systemName: "person.crop.rectangle")
        }
    }
}

class ProfileFilterViewCell: UICollectionViewCell{
    
    // MARK: - Properties
    
    //Publier ou taguer la liste des publications Défini pour changer l'image de imageView lorsque l'un ou l'autre est mis à jour
    var option: ProfileFilterOptions! {
        didSet{ imageView.image = option.systemImage }
    }
    
    private var imageView: UIImageView = {
        let iv = UIImageView()
        return iv
    }()
    
    //Changer la teinte Couleur selon qu'elle est sélectionnée ou non
    override var isSelected: Bool {
        didSet{
            imageView.tintColor = isSelected ? .black : .lightGray
        }
    }
    
    // MARK: - Lifecycle
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        addSubview(imageView)
        imageView.tintColor = .lightGray
        imageView.setDimensions(width: 24, height: 24)
        imageView.center(inView: self)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Maintenant, je suis à bout de souffle pour écrire un article, mais passons à l'étape 6.

6. Créez PostCell pour afficher les photos publiées dans le dossier Afficher

Maintenant, créons rapidement une cellule qui n'affiche que les photos à la fin! !!

PostCell.swift


import UIKit

class PostCell: UICollectionViewCell{
    
    // MARK: - Properties
    
    let postImageView: UIImageView = {
        let iv = UIImageView()
        iv.contentMode = .scaleAspectFill
        iv.clipsToBounds = true
        return iv
    }()
    
    
    // MARK: - Lifecycle
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        self.layer.borderColor = UIColor.white.cgColor
        self.layer.borderWidth = 0.5
        
        addSubview(postImageView)
        postImageView.addConstraintsToFillView(self)
        postImageView.center(inView: self)
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Je suis entré en mode Life Easy à la fois, alors faisons correspondre tout avec ProfileController à la fin! !!

7. Combiné et terminé! !!

ProfileController.swift


import UIKit

private let filterViewIdentifier = "filterView"
private let profileHeaderCellIdentifier = "profileHeaderCell"
private let postCellIdentifier = "postCell"

class ProfileController: UICollectionViewController{
    
    // MARK: - Properties
    
    //Créez une séquence Haribote UIIMage que vous souhaitez adapter à l'emplacement de la cellule post
    private var imageArray: [UIImage?] =
        [UIImage(named: "jeff"), UIImage(named: "zack"), UIImage(named: "elon"), UIImage(named: "steve"),
         UIImage(named: "jeff"), UIImage(named: "zack"), UIImage(named: "elon"), UIImage(named: "steve"),
         UIImage(named: "jeff"), UIImage(named: "zack"), UIImage(named: "elon"), UIImage(named: "steve"),
         UIImage(named: "jeff"), UIImage(named: "zack"), UIImage(named: "elon"), UIImage(named: "steve")]
    
    
    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureUI()
    }
    
    
    // MARK: - Selectors
    
    @objc func handleRightButtonTapped(){
        print("DEBUG: you pressed the button..")
    }
    
    @objc func handleRefresh(){
        //Ne rien faire car il n'y a pas de données
        collectionView.refreshControl?.beginRefreshing()
        collectionView.refreshControl?.endRefreshing()
    }
    
    // MARK: - Helpers
    
    func configureUI(){
        view.backgroundColor = .systemGroupedBackground
        
        configureNavigationBar()
        configureCollectionView()
        
        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
        collectionView.refreshControl = refreshControl
    }
    
    
    func configureNavigationBar(){
        navigationController?.navigationBar.tintColor = .black
        navigationController?.navigationBar.barTintColor = .systemGroupedBackground
        navigationController?.navigationBar.isTranslucent = false
        navigationController?.navigationBar.shadowImage = UIImage()
        
        navigationItem.title = "user_id"
        navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "line.horizontal.3"), style: .plain, target: self, action: #selector(handleRightButtonTapped))
        
    }
    
    func configureCollectionView(){
        collectionView.backgroundColor = .systemGroupedBackground
        
        collectionView.register(ProfileHeader.self, forCellWithReuseIdentifier: profileHeaderCellIdentifier)
        collectionView.register(PostCell.self, forCellWithReuseIdentifier: postCellIdentifier)
        
        collectionView.register(ProfileFilterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: filterViewIdentifier)
        
        guard let tabHeight = tabBarController?.tabBar.frame.height else { return }
        collectionView.contentInset.bottom = tabHeight
        
        //Assimiler FilterView avec navigationBar lors du défilement
        guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
        flowLayout.sectionHeadersPinToVisibleBounds = true
    }
}

// MARK: - UICollectionViewDataSource

extension ProfileController{
    
    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
    
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        switch section {
        case 0:
            return 1
        default:
            //Placez autant de cellules que vous souhaitez afficher
            return imageArray.count
        }
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        switch indexPath.section {
        case 0:
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: profileHeaderCellIdentifier, for: indexPath) as! ProfileHeader
            return cell
        default:
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: postCellIdentifier, for: indexPath) as! PostCell
            //Attribuer à l'image de la cellule
            cell.postImageView.image = imageArray[indexPath.row]
            return cell
        }
    }
    
    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        //Enregistrement ProfileFilterView comme en-tête
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: filterViewIdentifier, for: indexPath) as! ProfileFilterView
        return header
    }
}

// MARK: - UICollectionViewDelegate

extension ProfileController{
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if(indexPath.section == 1){
          print("DEBUG: this item is \(indexPath.row)")
        }
    }
}
// MARK: - UICollectionViewDelegateFlowLayout

extension ProfileController: UICollectionViewDelegateFlowLayout{
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        switch section {
        case 0:
            return CGSize(width: 0, height: 0)
        default:
            let height: CGFloat = 50
            return CGSize(width: view.frame.width, height: height)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        switch indexPath.section {
        case 0:
            let height: CGFloat = 340
            return CGSize(width: view.frame.width, height: height)
        default:
            //Affichage à 3 colonnes, taille carrée
            let size = view.frame.width / 3
            return CGSize(width: size, height: size)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
}

finalement

Et ça? Avez-vous terminé l'interface utilisateur Haribote semblable à un profil Instagram?

Vers la fin, je me fatiguais et le nombre de mots diminuait. Je voudrais ajouter que je voudrais vous dire dans les commentaires, par exemple où l'explication est insuffisante.

Ou plutôt, je suis désolé s'il y a une plainte selon laquelle cela ne fonctionne pas même si je le copie. Je vais le réparer tout de suite.

Eh bien!

Recommended Posts

[Swift] J'ai essayé d'implémenter une interface utilisateur semblable à un profil Instagram avec UICollectionView avec juste du code sans storyboard
Comment implémenter UICollectionView avec du code uniquement dans Swift
J'ai essayé d'utiliser Realm avec Swift UI
[iOS] J'ai essayé de créer une application de traitement de type insta avec Swift
J'ai essayé d'implémenter le téléchargement de fichiers avec Spring MVC
[Java 11] J'ai essayé d'exécuter Java sans compiler avec javac
J'ai essayé d'implémenter Sterling Sort avec Java Collector
J'ai essayé d'implémenter la fonction de prévisualisation d'image avec Rails / jQuery
J'ai essayé d'implémenter un mappage OU flexible avec MyBatis Dynamic SQL
J'ai essayé d'interagir avec Java
J'ai essayé de migrer le traitement vers VS Code
J'ai essayé de démarrer avec Web Assembly
J'ai essayé d'implémenter le modèle Iterator
Les débutants rapides ont essayé d'implémenter la logique micro-ondes!
J'ai essayé d'implémenter une fonction équivalente à Felica Lite avec HCE-F d'Android
J'ai essayé de vérifier AdoptOpenJDK 11 (11.0.2) avec l'image Docker
J'ai essayé de faire une authentification de base avec Java
J'ai essayé d'implémenter des relations polymorphes à Nogizaka.
J'ai essayé de gérer la configuration des jambes de force avec Coggle
J'ai essayé de gérer les informations de connexion avec JMX
Les débutants rapides ont essayé de mettre en œuvre la logique des distributeurs automatiques!
J'ai essayé d'implémenter un serveur en utilisant Netty
J'ai essayé de casser le bloc avec java (1)
J'ai essayé ce que je voulais essayer avec Stream doucement.
J'ai essayé de lire et de sortir CSV avec Outsystems
J'ai essayé d'implémenter la notification push Firebase en Java
J'ai démarré MySQL 5.7 avec docker-compose et j'ai essayé de me connecter
J'ai essayé de démarrer avec Spring Data JPA
J'ai essayé de dessiner une animation avec l'API Blazor + canvas
[Java] J'ai essayé de mettre en œuvre la recherche de produits de l'API Yahoo
J'ai essayé d'implémenter la méthode de division mutuelle d'Eugrid en Java
Lorsque j'ai essayé de faire défiler automatiquement avec JScrollBar, le gestionnaire d'événements n'a été dessiné qu'une seule fois.