[Swift] Ich habe versucht, mit UICollectionView eine Instagram-ähnliche Benutzeroberfläche mit nur Code ohne Storyboard zu implementieren

Einführung

Dieses Mal werde ich versuchen, eine Instagram-Profil-ähnliche Benutzeroberfläche mit UICollectionView nur mit Code zu implementieren. Ist der Inhalt

Ich hoffe dieser Artikel hilft jemandem

Es ist nur ein Swift-Anfänger, der die Benutzeroberfläche imitiert hat. Ich denke, es gibt einige Punkte, die nicht erreicht werden können. Wenn Sie Fehler beim Schreiben des Codes bemerken, geben Sie uns bitte einen Rat! !!

Drei Monate bevor ich anfing zu schreiben, hört Piempaon nicht auf

Vollständiges Formular

last_qiita.gif

[Instagrammer, der sich wirklich nach Unternehmern sehnt]

Zielgruppe

・ Anfänger der iOS-Anwendungsentwicklung ・ Diejenigen, die wissen möchten, wie UICollectionView verwendet wird ・ Diejenigen, die sich ohne StoryBoard entwickeln möchten ・ Diejenigen, die Instagram UI mögen

Entwicklungsumgebung

・ Version 11.3 (11C29) ・ Schnell 5

Abgeschlossene Version Github

Ich werde den Quellcode unten setzen

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

Dateiorganisation

Dieses Mal werden wir neue Dateien in den Ordnern "Ansicht" und "Controller" hinzufügen, da wir keine Kommunikation wie Datenerfassung durchführen. Utils> Extensions.swift enthält Funktionen zur Vereinfachung der layoutbezogenen Verarbeitung. Ich werde in diesem Artikel nicht auf Details eingehen, daher wäre es hilfreich, wenn Sie es von Github kopieren könnten.

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

Fahren wir nun mit der Implementierung fort

Implementierungsverfahren

Überspringen Sie für 1 und 2, wenn Sie keine TabBar benötigen

  1. Erstellen Sie eine zu verwendende Controller-Datei
  2. Verwenden Sie UITabBarController, um zu bestimmen, welcher Controller als TabBar angezeigt werden soll
  3. Bestimmen Sie in SceneDelegate.swift den Controller, der beim Start angezeigt werden soll
  4. Erstellen Sie ProfileHeaderCell im Ansichtsordner
  5. Erstellen Sie FilterView im Ansichtsordner
  6. Erstellen Sie eine PostCell für die Anzeige der veröffentlichten Fotos im Ordner "Ansicht"
  7. Kombiniert und abgeschlossen! !!

1. Erstellen Sie eine zu verwendende Controller-Datei

Hier erstellen wir eine Controller-Datei für TabBar, die in 2 implementiert ist. Auf Instagram können 5 Registerkarten angezeigt werden. Erstellen Sie also 5 Dateien direkt unter dem Controller-Ordner.

ProfileController.swift


import UIKit

class ProfileController: UICollectionViewController{

  override func viewDidLoad() {
    super.viewDidLoad()

  }

}

Für die anderen 4 Dateien ist das Folgende in Ordnung

FeedController.swift



import UIKit

class FeedController: UIViewController{

  override func viewDidLoad() {
    super.viewDidLoad()

    //Geben Sie die Zeichenfolge ein, die in der Navigationsleiste angezeigt werden soll
    navigation.item = "Post"
  }

}

2. Verwenden Sie UITabBarController, um den Controller festzulegen, der als TabBar angezeigt werden soll

Erstellen Sie "MainTabController.swift" direkt unter dem Ordner "controller", um die in 1 erstellte Datei mit TabBar zu verknüpfen.

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)
        //Wird so angezeigt, als ob 2 Benachrichtigungen empfangen wurden
        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)
        
        //Entscheiden Sie, welcher Controller in der Registerkartenleiste platziert werden soll
        viewControllers = [nav1, nav2, nav3, nav4, nav5]
        
        //Erstanzeige von profileController
        selectedIndex = 4
    }
    
    //Funktion zum Festlegen eines beliebigen rootViewController-, tabIcon-Bildes,Wird in configureViewControllern verwendet
    func templateNavigationController(image: UIImage?, rootViewController: UIViewController) -> UINavigationController{
        let nav = UINavigationController(rootViewController: rootViewController)
        nav.tabBarItem.image = image
        nav.navigationBar.tintColor = .white
        return nav
    }
}

3. Bestimmen Sie in SceneDelegate.swift den Controller, der beim Start angezeigt werden soll

Jetzt bearbeiten wir "SceneDelegate.swift" und setzen "MainTabController" so, dass es beim Start angezeigt wird.

SceneDelegate.swift



class SceneDelegate: UIResponder, UIWindowSceneDelegate {

  //Kürzung
  
    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()
    }

  //Kürzung
}

Wenn Sie Simulator nach dem Einstellen hier starten, ist es perfekt, wenn Folgendes angezeigt wird スクリーンショット 2020-09-28 20.04.35.png

4. Erstellen Sie ProfileHeaderCell im Ansichtsordner

Als Nächstes erstellen wir eine Ansicht, die auf ProfileController angewendet werden soll Ich werde es im folgenden Format erstellen, aber zuerst erstellen wir hier eine ProfileHeaderCell des Profilumriss-Teils

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

Erstellen Sie eine Datei von ProfileHeader.swift direkt unter View

ProfileHeader.swift


import UIKit

//Es muss nicht sein, weil es ein Haribote ist
protocol ProfileHeaderDelegate: class {
    func handleEditProfile(_ header: ProfileHeader)
}

class ProfileHeader: UICollectionViewCell{
    
    // MARK: - Properties
    
    //Es muss nicht sein, weil es ein Haribote ist
    weak var delegate: ProfileHeaderDelegate?
    
    private let profileImageView: UIImageView = {
        let iv = UIImageView()
        iv.contentMode = .scaleAspectFit
        iv.clipsToBounds = true
        iv.image = UIImage(named: "Bitte fügen Sie ein Foto entsprechend ein")
        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: "Post")
    private lazy var followingCountLabel = makeStatsTitle(withTitle: "folgenden")
    private lazy var followerCountLabel = makeStatsTitle(withTitle: "Anhänger")
    
    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 = "Dies ist ein Versuch, die Benutzeroberfläche des Instagram-Profils zu imitieren. Korrekt. Es ahmt nur nach."
        label.font = UIFont.systemFont(ofSize: 14)
        label.numberOfLines = 3
        return label
    }()
    
    private let editProfileButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Profil bearbeiten", 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 = "Neu"
        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
    
    //Es muss nicht sein, weil es ein Haribote ist
    @objc func handleEditProfileButtonTapped(){
        delegate?.handleEditProfile(self)
    }
    
    
    // MARK: - Helpers
    
    //Zum Erstellen einer StackView, die die Anzahl der Schaltflächen und Details vertikal ausrichtet
    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
    }
    
    //Zum Erstellen von Anzeigeschaltflächen wie der Anzahl der Beiträge und Follower
    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
    }
    //Zum Erstellen von Beschriftungen zum Anzeigen der Anzahl der Beiträge und Details, z. B. Follower
    private func makeStatsTitle(withTitle title: String) -> UILabel{
        let label = UILabel()
        label.text = title
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 14)
        return label
    }
}

Wenden wir dies auf ProfileController an (überspringen Sie es einmal in 5 und 6).

ProfileController.swift


import UIKit

private let profileHeaderCell = "ProfileHeaderCell"

class ProfileController: UICollectionViewController{
    
    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureUI()
    }
    
    // MARK: - Selectors
    
    //Ornament
    @objc func handleRightButtonTapped(){
        print("DEBUG: you pressed the button..")
    }
    
    @objc func handleRefresh(){
        //Tun Sie nichts, weil es keine Daten gibt
        collectionView.refreshControl?.beginRefreshing()
        collectionView.refreshControl?.endRefreshing()
    }
    
    // MARK: - Helpers
    
    //Ganze UI-Einstellungen
    func configureUI(){
        view.backgroundColor = .systemGroupedBackground
        
        configureNavigationBar()
        configureCollectionView()
        
        //Wischen Sie nach unten, um die Windeinstellungen neu zu laden
        let refreshControl = UIRefreshControl()
        refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged)
        collectionView.refreshControl = refreshControl
    }
    
    //Einstellungen in Bezug auf die Navigationsleiste
    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
        
        //Registrierung des Profilkopfs
        collectionView.register(ProfileHeader.self, forCellWithReuseIdentifier: profileHeaderCell)
        
        //Platzieren Sie collectionView so, dass es tabBar nicht abdeckt
        guard let tabHeight = tabBarController?.tabBar.frame.height else { return }
        collectionView.contentInset.bottom = tabHeight
    }
}

// MARK: - UICollectionViewDataSource / UICollectionViewDelegate

extension ProfileController{
    
    //Setzen Sie die Anzahl der Abschnitte vorerst auf 1 → Wechseln Sie nach dem Einstellen von PostCell auf 2
    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    //Anzahl der Zellen, die im Abschnitt angezeigt werden sollen → Es ist nur einmal ein Profilkopf erforderlich
    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }
    
    //Einstellung der anzuzeigenden Zelle
    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{
    
    //Einstellung der Zellengröße → Bitte ändern Sie die Höhe entsprechend
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        return CGSize(width: view.frame.width, height: 340)
    }
}

Wenn Sie den Simulator bisher starten, wird der Profil-Header-Teil angezeigt! Vielleicht! Lassen Sie uns von hier bis zum Ende schnell fertig werden

5. Erstellen Sie FilterView im Ansichtsordner

FilterView ist ein Filterteil zum Anzeigen Ihrer eigenen Beitragsliste oder einer von Ihren Freunden getaggten Liste. In ProfileController wird es als Header mit indexPath.section = 1 angezeigt

Erstellen Sie es jetzt für FilterView, indem Sie UICollectionView in UICollectionReusableView installieren. Ja, das heißt, die FilterViewCell von UICollectionViewCell wird auch in einer separaten Datei erstellt. geben wir unser Bestes

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?
    
    //collectionView, die angezeigt werden soll
    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
    }()
    
    //Animieren Sie diesen Kerl, um ein gut ausgewähltes Gefühl zu erzeugen
    private let underlineView: UIView = {
        let view = UIView()
        view.backgroundColor = .black
        return view
    }()
    
    //Grenzlinie mit 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)
        
        //Wird bei der Initialisierung ausgewählt=Bestimmen Sie, welche Zelle wahr sein soll
        let selectedIndexPath = IndexPath(row: 0, section: 0)
        collectionView.selectItem(at: selectedIndexPath, animated: true, scrollPosition: .left)
        
        addSubview(collectionView)
        //Erweitern Sie die Sammlungsansicht, um die übergeordnete Ansicht zu füllen
        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 {
        //Da es zwei Möglichkeiten für Tag oder Post gibt, ist Return 2 in Ordnung
        return ProfileFilterOptions.allCases.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ProfileFilterCell
        
        //Update-Option auf der Zellenseite
        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 bis zur x-Koordinate der Zelle touchUpInside the underlineView.Bewegen Sie sich in 3 Sekunden
        let xPosition = cell?.frame.origin.x ?? 0
        
        UIView.animate(withDuration: 0.3) {
            self.underlineView.frame.origin.x = xPosition
        }
        
        //Haribote → Ursprünglich verarbeiten und schreiben, damit das Anzeigebild mit ProfileController geändert werden kann
        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)
    }
    
    //Installiert, damit keine Lücken zwischen den Elementen entstehen
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
}

ProfileFilterViewCell.swift


import UIKit

//Beiträge oder Tagging Beitragsliste Bestimmen Sie, welche
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
    
    //Post- oder Tag-Post-Liste Legen Sie fest, dass das Bild von imageView geändert werden soll, wenn eines der beiden aktualisiert wird
    var option: ProfileFilterOptions! {
        didSet{ imageView.image = option.systemImage }
    }
    
    private var imageView: UIImageView = {
        let iv = UIImageView()
        return iv
    }()
    
    //Ändern Sie tintColor abhängig davon, ob es ausgewählt ist oder nicht
    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")
    }
}

Jetzt bin ich außer Atem, um einen Artikel zu schreiben, aber fahren wir mit Schritt 6 fort.

6. Erstellen Sie PostCell, um die veröffentlichten Fotos im Ordner "Ansicht" anzuzeigen

Jetzt erstellen wir schnell eine Zelle, in der am Ende nur Fotos angezeigt werden! !!

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")
    }
}

Ich bin sofort in den Life Easy-Modus gewechselt, also lassen Sie uns am Ende alles mit ProfileController abgleichen! !!

7. Kombiniert und abgeschlossen! !!

ProfileController.swift


import UIKit

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

class ProfileController: UICollectionViewController{
    
    // MARK: - Properties
    
    //Erstellen Sie eine Haribote UIIMage-Sequenz, die Sie an den Speicherort der Postzelle anpassen möchten
    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(){
        //Tun Sie nichts, weil es keine Daten gibt
        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
        
        //Assimilieren Sie FilterView beim Scrollen mit der Navigationsleiste
        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:
            //Platzieren Sie so viele Zellen, wie Sie anzeigen möchten
            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
            //Dem Bild der Zelle zuweisen
            cell.postImageView.image = imageArray[indexPath.row]
            return cell
        }
    }
    
    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        //ProfileFilterView-Registrierung als Header
        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:
            //Anzeige mit 3 Spalten, quadratische Größ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
    }
}

Schließlich

Wie wär es damit? Hast du die Instagram-Profil-ähnliche Haribote-Benutzeroberfläche fertiggestellt?

Gegen Ende wurde ich müde und die Anzahl der Wörter nahm ab. Ich möchte hinzufügen, dass ich Ihnen in den Kommentaren mitteilen möchte, wo die Erklärung unzureichend ist.

Oder besser gesagt, es tut mir leid, wenn es eine Beschwerde gibt, dass es nicht funktioniert, auch wenn ich es kopiere. Ich werde es sofort reparieren.

Na dann!

Recommended Posts

[Swift] Ich habe versucht, mit UICollectionView eine Instagram-ähnliche Benutzeroberfläche mit nur Code ohne Storyboard zu implementieren
So implementieren Sie UICollectionView mit Code nur in Swift
Ich habe versucht, Realm mit Swift UI zu verwenden
[iOS] Ich habe versucht, mit Swift eine insta-ähnliche Verarbeitungsanwendung zu erstellen
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
[Java 11] Ich habe versucht, Java auszuführen, ohne mit Javac zu kompilieren
Ich habe versucht, Sterling Sort mit Java Collector zu implementieren
Ich habe versucht, die Bildvorschau mit Rails / jQuery zu implementieren
Ich habe versucht, eine flexible ODER-Zuordnung mit MyBatis Dynamic SQL zu implementieren
Ich habe versucht, mit Java zu interagieren
Ich habe versucht, Processing auf VS Code zu migrieren
Ich habe versucht, mit Web Assembly zu beginnen
Ich habe versucht, das Iterator-Muster zu implementieren
Schnelle Anfänger versuchten, Mikrowellenlogik zu implementieren!
Ich habe versucht, mit HCE-F von Android eine Funktion zu implementieren, die Felica Lite entspricht
Ich habe versucht, AdoptOpenJDK 11 (11.0.2) mit dem Docker-Image zu überprüfen
Ich habe versucht, eine Standardauthentifizierung mit Java durchzuführen
Ich habe versucht, polymorph in Nogizaka zu implementieren.
Ich habe versucht, die Federbeinkonfiguration mit Coggle zu verwalten
Ich habe versucht, Anmeldeinformationen mit JMX zu verwalten
Schnelle Anfänger haben versucht, die Automatenlogik zu implementieren!
Ich habe versucht, einen Server mit Netty zu implementieren
Ich habe versucht, den Block mit Java zu brechen (1)
Ich habe versucht, was ich mit Stream leise versuchen wollte.
Ich habe versucht, CSV mit Outsystems zu lesen und auszugeben
Ich habe versucht, die Firebase-Push-Benachrichtigung in Java zu implementieren
Ich habe MySQL 5.7 mit Docker-Compose gestartet und versucht, eine Verbindung herzustellen
Ich habe versucht, mit Spring Data JPA zu beginnen
Ich habe versucht, Animationen mit der Blazor + Canvas-API zu zeichnen
[Java] Ich habe versucht, die Yahoo API-Produktsuche zu implementieren
Ich habe versucht, die Methode der gegenseitigen Teilung von Eugrid in Java zu implementieren
Als ich versuchte, mit JScrollBar automatisch zu scrollen, wurde der Ereignishandler nur einmal gezeichnet.