Πώς να δημιουργήσετε μέσω προγραμματισμού έναν κλώνο Spotify για iOS με το AutoLayout

Σε αυτήν την ανάρτηση θα προσπαθήσουμε να δημιουργήσουμε ξανά τη διάταξη της αρχικής οθόνης Spotify στο Swift μέσω προγραμματισμού. Γιατί μέσω προγραμματισμού; Νομίζω ότι είναι πάντα καλό να γνωρίζεις πώς να φτιάχνεις πράγματα με διαφορετικούς τρόπους και μου αρέσει να γράφω κώδικα για να κάνω πράγματα με προγραμματισμό. Αυτές οι δεξιότητες είναι ιδιαίτερα χρήσιμες εάν εργάζεστε με ομάδα ή χρησιμοποιείτε έλεγχο έκδοσης.

Αυτή είναι η πραγματική αρχική οθόνη της εφαρμογής Spotify για κινητά. Έτσι, για να επιτύχουμε αυτό το είδος διάταξης, θα χρησιμοποιούμε UICollectionViewκαι μπορεί να χρησιμοποιήσουμε TabBarControllerεπίσης για να δημιουργήσουμε το πρόγραμμα πλοήγησης καρτελών.

Βασική απαίτηση: Πρώτα βεβαιωθείτε ότι έχετε εγκαταστήσει το Xcode +10 και το γρήγορο +4.

Ας ξεκινήσουμε δημιουργώντας ένα νέο έργο Xcode χρησιμοποιώντας το Xcode:

Και το πρώτο πράγμα που πρέπει να κάνουμε ViewController.swiftείναι να αλλάξουμε το superClass σε UICollectionViewControllerαντί   UIViewControllerγιατί θα βασίζεται η τάξη μας collectionView.

// // ViewController.swift // spotifyAutoLayout // // Created by admin on 10/31/19. // Copyright © 2019 Said Hayani. All rights reserved. // import UIKit class ViewController: UICollectionViewController { override func viewDidLoad() { super.viewDidLoad() collectionView.backgroundColor = .purple // Do any additional setup after loading the view. } } 

Εάν προσπαθήσετε να εκτελέσετε την εφαρμογή, η έκδοση θα αποτύχει. Πρέπει να προσθέσουμε κάποιο κώδικα στο AppDelegate.swiftαρχείο μέσα στη didFinishLaunchingWithOptionsσυνάρτηση μετά από αυτό το κομμάτι κώδικα πριν από τη   returnδήλωση:

 let layout = UICollectionViewFlowLayout() window = UIWindow() window?.rootViewController = ViewController(collectionViewLayout: layout)

Και ο κώδικας πρέπει να έχει την εξής μορφή:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. let layout = UICollectionViewFlowLayout() window = UIWindow() window?.rootViewController = ViewController(collectionViewLayout: layout) return true }

Τώρα θα πρέπει να μπορείτε να εκτελέσετε την εφαρμογή και να δείτε την backgroundColorαλλαγή σε purple:

Το επόμενο βήμα είναι να διανείμετε τη διάταξη και να διαιρέσετε το χώρο εξίσου μεταξύ των ενοτήτων.

Ας καθορίσουμε τις μεθόδους μας CollectionView.

Τα βήματα:

  • Καταχωρήστε ένα επαναχρησιμοποιήσιμο κελί με μοναδικό αναγνωριστικό
  • Ορίστε τον αριθμό των αντικειμένων στην ενότητα
  • Χρησιμοποιήστε το καταχωρημένο κελί  

Για να χρησιμοποιήσουμε κάποιες από τις CollectionViewμεθόδους που πρέπει να συμμορφωνόμαστε πάντα UICollectionViewDelegateFlowLayoutως superClass και να έχουμε την αυτόματη συμπλήρωση των μεθόδων. Ας ξεκινήσουμε λοιπόν με την εγγραφή του CollectionViewCell.

Στο εσωτερικό View.DidLoad()καλούμε τη collectionView.register()μέθοδο για την καταχώριση του επαναχρησιμοποιήσιμου κελιού:

 collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)

Στη συνέχεια, ορίζουμε τον αριθμό των κελιών που θα έχουμε μέσα στη collectionViewχρήση numberOfItemsInSection. Προς το παρόν πρέπει να φτιάξουμε 5 αντικείμενα:

 override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 5 }

Το επόμενο βήμα είναι να ορίσετε το επαναχρησιμοποιήσιμο κελί χρησιμοποιώντας cellForItemAtαυτό που πρέπει να επιστρέψει UICollectionViewCellκαι να έχει ένα μοναδικό αναγνωριστικό που ονομάζεται cellId. Ο κωδικός μοιάζει με αυτόν:

 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) cell.backgroundColor = .red return cell }

Ο πλήρης κωδικός πρέπει να έχει την εξής μορφή:

import UIKit class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { let cellId : String = "cellId" override func viewDidLoad() { super.viewDidLoad() collectionView.backgroundColor = .purple collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId) } override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 5 } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) cell.backgroundColor = .red return cell } }

Θα πρέπει να μπορείτε να δείτε 5 στοιχεία με κόκκινο φόντο στην οθόνη:

Προσθέστε ένα προσαρμοσμένο πλάτος και ύψος στα κελιά

Τώρα πρέπει να τοποθετήσουμε τα κελιά στη σωστή σειρά και να τους δώσουμε ένα widthκαι height. Κάθε κελί θα λάβει widthτην οθόνη ως width.

Είμαστε τυχεροί που έχουμε sizeForItemAtμέθοδο, ώστε να μπορούμε να δώσουμε στα κελιά μια συνήθεια widthκαι height. Είναι μια μέθοδος που πρέπει να επιστρέφει έναν CGSizeτύπο:

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = view.frame.width let height = CGFloat(200) return CGSize(width: width, height: height) }

Έτσι κάναμε τη   Cellλήψη widthτης οθόνης χρησιμοποιώντας view.frame.widthκαι ένα έθιμο heightμε έναν CGFloatτύπο.

Τώρα μπορείτε να δείτε το αποτέλεσμα παρακάτω στον Προσομοιωτή σας:

Τα πάντα φαίνονται καλά μέχρι τώρα. Αυτή τη φορά ας δημιουργήσουμε ένα προσαρμοσμένο κελί που μπορεί να επαναχρησιμοποιηθεί. Δημιουργήστε ένα νέο αρχείο Swift με το όνομα CustomCell:

CustomCell.swift θα πρέπει να μοιάζει με αυτό παρακάτω:

 import UIKit class CustomCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 

Τώρα τα επόμενα πράγματα που πρέπει να κάνουμε είναι να τροποποιήσουμε δύο μεθόδους για να υποστηρίξουμε το επαναχρησιμοποιήσιμο κελί collectionView.registerκαι cellForItemAt. Ας τροποποιήσουμε πρώτα τη μέθοδο εγγραφής. ΑντικαθιστώUICollectionViewCell.selfμε CustomCell:

 collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId) 

Στη συνέχεια πρέπει να κάνουμε μετάδοση cellForItemAtγια να συμμορφωθούμε CustomCellόπως παρακάτω

 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell

Εάν εκτελέσετε την εφαρμογή, πιθανότατα δεν θα παρατηρήσετε καμία αλλαγή, οπότε δώστε στο CustomCell ένα BackgroundColor backgroundColor = .yellow. Μην ξεχάσετε να αφαιρέσετε τη γραμμή cell.backgroundColor = .redσε cellForItemAt. Θα πρέπει να δείτε το χρώμα του φόντου να αλλάζει σε κίτρινο;

Τώρα ήρθε η ώρα να βάλουμε λίγο αλάτι CutomCell: D

Αν κοιτάξετε την αρχική οθόνη του Spotify, κάθε ενότητα που είναι CustomCellστο παράδειγμά μας περιέχει έναν τίτλο ενότητας, δευτερεύοντα κελιά και είναι οριζόντια:

Προσθέστε έναν τίτλο ενότητας

Ας προσθέσουμε μια ετικέτα τίτλου στο κελί. Δημιουργήστε το titleLabelστοιχείο μέσα στην CutomCellτάξη:

let titleLabel: UILabel = { let lb = UILabel() lb.text = "Section Title" lb.font = UIFont.boldSystemFont(ofSize: 14) lb.font = UIFont.boldSystemFont(ofSize: 14) return lb }()

Στη συνέχεια, προσθέστε το στοιχείο στην προβολή μέσα στο init()μπλοκ:

addSubview(titleLabel)

Εάν εκτελέσετε την εφαρμογή δεν θα δείτε καμία αλλαγή, και αυτό οφείλεται στο γεγονός ότι δεν έχουμε θέσει ακόμη κανένα περιορισμό στο στοιχείο. Ας προσθέσουμε λοιπόν περιορισμούς - προσθέστε αυτήν την ιδιότητα              lb.translatesAutoresizingMaskIntoConstraints = falseπρος τοtitleLabel για να μπορείτε να εφαρμόσετε περιορισμούς στο στοιχείο:

Αφού προσθέσουμε titleLabelστην προβολή, καθορίζουμε τους περιορισμούς:

 addSubview(titleLabel) titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = truetitleLabel.leftAnchor.constraint(equalTo: leftAnchor,constant: 8 ).isActive = true

Πάντα φροντίστε να προσθέσετε .isActive = trueιδιότητα - χωρίς αυτήν ο περιορισμός δεν θα λειτουργήσει!

Πριν προχωρήσουμε στο επόμενο μέρος, ας αλλάξουμε πρώτα το χρώμα φόντου της οθόνης σε μαύρο και επίσης αφαιρέσουμε το κίτρινο χρώμα για τα κελιά:

Now comes the big part: putting sub cells into each cell. To achieve that we are going to add a CollectionView inside CustomCell.

To add a CollectionView inside UICollectionViewCell we need to add  properties UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, and UICollectionViewDataSource as superClass to CustomCell.

Let's create the collectionView element as any simple view:

 let collectionView : UICollectionView = { // init the layout let layout = UICollectionViewFlowLayout() // set the direction to be horizontal layout.scrollDirection = .horizontal // the instance of collectionView let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) // Activate constaints cv.translatesAutoresizingMaskIntoConstraints = false return cv }()

Notice that we add layout to the collectionView as layer in the initializer as we did the first time with the viewController.swift. Here we also specify the direction of the FlowLayout to be .horizontal.

Let's add the collectionView element to the view as subView.

We gonna make a function that do that for us to make the code a little bit cleaner.

 fileprivate func setupSubCells(){ // add collectionView to the view addSubview(collectionView) collectionView.dataSource = self collectionView.delegate = self // setup constrainst // make it fit all the space of the CustomCell collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true collectionView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true collectionView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true } 

Make sure to set delegate to self for the collectionView and the dataSource as well:

 collectionView.dataSource = self

  collectionView.delegate = self

Then call the function within init block.

Xcode will display some errors if you trying to build the app because we are not conforming to UICollectionViewDelegate and UICollectionViewDelegateFlowLayout protocols. To fix that we need first to register the sub cell as a reusable cell.

Create a variable at the top of the class and give it a name of cellId so we can use it when we need the cell identifier:

let cellId : String = "subCellID"

collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)

Now we're missing two more methods to make the errors go away: numberOfItemsInSection that define the number of cells in the section and cellForItemAt that define the reusable cell. These methods are necessary for  collectionView to work properly:

 // number of cells func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 4 } // reusable Cell func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) cell.backgroundColor = .yellow return cell }

The results should look like this:

As you can see, the collectionView are in purple as background and sub cells are yellow.

Τα τελευταία πράγματα που μπορούμε να κάνουμε προτού τερματίσουμε αυτό το άρθρο είναι να subCellsέχουμε το ύψος της ενότητας και το πλάτος. Και πάλι χρησιμοποιούμε sizeForItemAtγια να ορίσουμε το heightκαι widthτο κελί.

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = frame.height let height = frame.height return CGSize(width: width, height: height) }

Και εδώ είμαστε;:

ΟΜΟΡΦΗ! Θα σταματήσω σε αυτό το σημείο, ώστε αυτή η ανάρτηση να μην είναι πολύ μεγάλη. Θα κάνω ένα δεύτερο μέρος όπου θα προσθέσουμε μερικές πλαστές εικόνες και θα την γεμίσω με κάποια δεδομένα.

Πλήρης πηγαίος κώδικας; εδώ

Παρακαλώ, εάν έχετε οποιεσδήποτε προσθήκες, ερωτήσεις ή διορθώσεις, δημοσιεύστε τα στα παρακάτω σχόλια; ή χτυπήστε με στο Twitter.

Εγγραφείτε στη λίστα email μου για να λαμβάνω ειδοποίηση κατά τη δημοσίευση του δεύτερου μέρους αυτού του σεμιναρίου