यह AutoLayout के साथ प्रोग्रामेटिकली Spotify UI क्लोन बनाने पर एक लेख का दूसरा भाग है। यदि आपने पहला भाग मिस कर दिया है, तो कोई चिंता नहीं - बस अभी जाकर इसे देखें।
इस लेख में, हम कुछ मॉक्ड तस्वीरें जोड़ने जा रहे हैं और UI को Spotify जैसा दिखाने का प्रयास करेंगे।
यह वही है जो हम आज करने जा रहे हैं ?
यह वह जगह है जहां हम पहले भाग में रुके थे:
अगला कदम कस्टमाइज़्ड सेल बनाना है। तो चलिए SubCustomCell नाम से एक बनाकर शुरू करते हैं।
सबसे पहले, प्रोजेक्ट फोल्डर के अंदर एक नई Swift फाइल बनाएं और इसे SubCustomCell.swift नाम दें। इस फाइल में हमारा कस्टम सेल होगा जो प्लेलिस्ट को रिप्रेजेंट करेगा। फाइल बनाने के बाद, नीचे दिए गए कोड को जोड़ने का प्रयास करें और सेल को इनिशियलाइज़ करें, शायद backgroundColor के साथ, collectionView के साथ सेल रजिस्टर करते समय UI परिवर्तन देखने के लिए।
import UIKit
class SubCustomCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .red
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
फिर हम SubCustomCell को CustomCell.swift के अंदर init ब्लॉक में रजिस्टर करते हैं। UICollectionViewCell.self को SubCustomCell से बदलें जैसे नीचे दिखाया गया है।
collectionView.register(SubCustomCell.self, forCellWithReuseIdentifier: cellId)
हमें cellForItemAt मेथड पर भी संशोधन करने की आवश्यकता है और इसे SubCustomCell के अनुरूप बनाएं जैसे निम्नलिखित।
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SubCustomCell
// cell.backgroundColor = .yellow
return cell
}
आपको backgroundColor red में बदला हुआ देखना चाहिए।
इस बिंदु तक सब कुछ सीधा और स्पष्ट होना चाहिए।
अब हम सेल्स को कुछ मॉक्ड तस्वीरों से भरने जा रहे हैं और प्रत्येक सेल के अंदर एक ImageView बनाएंगे। मैंने पहले से ही pexels.com से कुछ रैंडम तस्वीरें डाउनलोड की हैं, लेकिन बेझिझक किसी भी तस्वीर का उपयोग करें जो आपको पसंद हो (इन सहित)। आप उन्हें GitHub पर प्रोजेक्ट फाइल्स में पा सकते हैं।
चलिए SubCustomCell.swift के अंदर UIImageView बनाते हैं और कुछ कंस्ट्रेंट बनाते हैं।
let ImageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .yellow
return iv
}()
और इसे init ब्लॉक के अंदर addSubView का उपयोग करके view में जोड़ें।
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(ImageView)
}
अब चलिए ImageView को कंस्ट्रेंट के साथ सेल के अंदर सारी जगह लेने दें।
ImageView.translatesAutoresizingMaskIntoConstraints = false
ImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
ImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
ImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
ImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
LeftAnchorसेल के बाएं एंकर को दर्शाता हैrightAnchorसेल के दाएं एंकर को दर्शाता हैbottomAnchorसेल के नीचे के एंकर को दर्शाता हैtopAnchorसेल के ऊपर के एंकर को दर्शाता है
ImageView के टॉप एंकर को सेल के टॉप एंकर के बराबर बनाकर (और ImageView के लेफ्ट, राइट, और बॉटम एंकर के लिए भी ऐसा ही करके) यह ImageView को SubCustomCell (सेल) की सारी जगह लेने के लिए बनाता है।
नोट: सबसे पहले आपको कंस्ट्रेंट को एलिमेंट्स पर लागू करने में सक्षम होने के लिए translatesAutoresizingMaskIntoConstraints का उपयोग करने की आवश्यकता है। यह भी मत भूलें कि isActive प्रॉपर्टी को कॉल करें और इसे true असाइन करें - ऐसा किए बिना कंस्ट्रेंट काम नहीं करेंगे और कुछ भी नहीं बदलेगा।
ImageView में एक इमेज होनी चाहिए, तो चलिए एक जोड़ते हैं।
let ImageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .yellow
// हमारे पास प्रोजेक्ट के अंदर >image1< फाइल है
iv.image = UIImage(named: "image1")
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
और यदि आप ऐप को बिल्ड और चलाते हैं, तो आपको परिणाम और तस्वीर दिखाई देनी चाहिए जिसे हमने SubCustomCell में जोड़ा था।
कूल ?. अब एक एलिमेंट है जिसे हमें SubCustomCell में जोड़कर खत्म करना चाहिए। हमें एक शीर्षक चाहिए जो प्लेलिस्ट के शीर्षक को रिप्रेजेंट करेगा: UILabel।
शीर्षक के लिए यह इस तरह होगा:
let TitleLabel: UILabel = {
let lb = UILabel()
lb.textColor = UIColor.lightGray
lb.font = UIFont.systemFont(ofSize: 16)
lb.font = UIFont.boldSystemFont(ofSize: 20)
lb.text = "Evening Music"
return lb
}()
मैंने वहां कुछ रैंडम टेक्स्ट डाला है - आप जो चाहें डाल सकते हैं। अगला कदम एलिमेंट को व्यू में जोड़ना और इसे कुछ कंस्ट्रेंट देना है। शीर्षक को ImageView के नीचे रखा जाएगा।
व्यू में जोड़ें:
addSubview(TitleLabel)
ImageView और TitleLabel दोनों के लिए कंस्ट्रेंट लागू करना
ImageView.translatesAutoresizingMaskIntoConstraints = false
ImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
ImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
ImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
ImageView.heightAnchor.constraint(equalToConstant: 240).isActive = true
ImageView.bottomAnchor.constraint(equalTo: TitleLabel.topAnchor).isActive = true
TitleLabel.translatesAutoresizingMaskIntoConstraints = false
TitleLabel.topAnchor.constraint(equalTo: ImageView.bottomAnchor, constant: 10).isActive = true
TitleLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 5).isActive = true
TitleLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -5).isActive = true
और चलिए चलते हैं!
हमने तस्वीर को सेल में अधिकांश जगह लेने के लिए बनाया, और बाकी शीर्षक द्वारा लिया जाता है। जैसा कि आप देख सकते हैं, आप प्रत्येक सेक्शन में क्षैतिज रूप से स्क्रॉल कर सकते हैं और पूरी स्क्रीन में लंबवत रूप से भी।
अब हम सेल्स में कुछ मॉक डेटा डालते हैं ताकि यह वास्तविक लगे। इसके लिए मैंने एक JSON फाइल बनाई जिसमें सेक्शन और प्लेलिस्ट के लिए कुछ रैंडम डेटा है।
पहले दो स्ट्रक्चर बनाते हैं, Section और Playlist। हम प्रत्येक स्ट्रक्चर के लिए एक अलग फाइल बनाते हैं।
section.swift
import Foundation
struct Section {
var title: String
var playlists: NSArray
init(dictionary: [String: Any]) {
self.title = dictionary["title"] as? String ?? ""
self.playlists = dictionary["playlists"] as? NSArray ?? []
}
}
playlist.swift
import Foundation
struct PlayList {
var title: String
var image: String
init(dictionary: [String: Any]) {
self.title = dictionary["title"] as? String ?? ""
self.image = dictionary["image"] as? String ?? ""
}
}
और फिर ViewController.swift के अंदर हम एक फंक्शन बनाते हैं जो हमारे लिए JSON लाता है और परिणामों को एक ऐरे में स्टोर करता है।
print("attempt to fetch Json")
if let path = Bundle.main.path(forResource: "test", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? [Any] {
// do stuff
jsonResult.forEach { (item) in
let section = Section(dictionary: item as! [String: Any])
// print("FEtching",section.playlists)
self.sections.append(section)
}
self.collectionView.reloadData()
}
} catch {
// handle error
}
}
fetchJson फंक्शन को ViewDidLoad मेथड के अंदर कॉल किया जाता है। हमारे पास एक वेरिएबल भी है जिसे sections कहा जाता है जहां हम परिणाम स्टोर करते हैं:
var sections = [Section]()
अगला कदम ViewController से CustomCell में डेटा पास करना है। इसके लिए हम CustomCell के अंदर एक वेरिएबल बनाते हैं जो प्रत्येक सेक्शन के लिए डेटा प्राप्त करेगा:
var section: Section? {
didSet {
print("section ✅", self.section)
}
}
हम ViewController मेथड के अंदर cellForItemAt का उपयोग करके डेटा को सीधे CustomCell में पास करते हैं।
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CustomCell
cell.section = sections[indexPath.item]
return cell
}
नोट: हम हर बार self.collectionView.reloadData() को कॉल करते हैं जब भी fetchJson को कॉल किया जाता है ताकि नीचे वाला ब्लॉक, CustomCell के अंदर, भी कॉल हो जाए। कंसोल चेक करें, shift + command + C:
var section: Section? {
didSet {
print("section ✅", self.section)
}
}
पहली चीज जो हम बदलते हैं वह है सेक्शन शीर्षक सेट करना:
var section: Section? {
didSet {
print("section ✅", self.section)
guard let section = self.section else { return }
self.titleLabel.text = section.title
}
}
और फिर आपको स्क्रीन पर प्रत्येक सेक्शन का एक विशिष्ट शीर्षक दिखाई देना चाहिए ?।
अब SubCustomCell में डेटा पास करने का समय है। हम वही चीज करते हैं जो हमने ऊपर किया था। हमें playlists ऐरे पास करने की आवश्यकता है, इसलिए हम CustomCell के अंदर playlists नामक एक वेरिएबल बनाते हैं।
var playlists: [PlayList]() //empty
पहले, हम JSON से playlists के माध्यम से मैप करते हैं। फिर हम प्रत्येक प्लेलिस्ट को playlists वेरिएबल के साथ जोड़ते हैं।
var section: Section? {
didSet {
print("section ✅", self.section)
guard let section = self.section else { return }
self.titleLabel.text = section.title
// प्लेलिस्ट ऐरे में जोड़ें
self.section?.playlists.forEach({ (item) in
let playlist = PlayList(dictionary: item as! [String: Any])
self.playlists.append(playlist)
})
self.collectionView.reloadData()
}
}
ध्यान दें! यदि आप ऐप चलाने की कोशिश करते हैं तो यह क्रैश हो सकता है। ऐसा इसलिए है क्योंकि हम सेक्शन की संख्या सेट करना भूल गए। चूंकि हम अब JSON से डेटा प्राप्त कर रहे हैं, संख्या JSON में हमारे पास मौजूद सेक्शन की संख्या के आधार पर डायनामिक होनी चाहिए। सेक्शन की संख्या JSON के अंदर सेक्शन की संख्या के बराबर होनी चाहिए, इसलिए हमें ViewController के अंदर numberOfItemsInSection को नीचे दिए गए अनुसार संशोधित करने की आवश्यकता है:
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return sections.count
}
हम CustomCell.swift के अंदर उसी मेथड के साथ वही चीज करते हैं - लेकिन यहां हम playlists की संख्या पर विचार करते हैं।
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.playlists.count
}
हमारे द्वारा पूरा किया जाने वाला अंतिम चरण CustomCell.swift में cellForItemAt के भीतर प्रत्येक सिंगल प्लेलिस्ट Object को SubCustomCell में पास करना है।
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SubCustomCell
// here ?
cell.playlist = playlists[indexPath.item]
return cell
}
और हम playlist वेरिएबल के माध्यम से SubCustomCell के अंदर उस डेटा को प्राप्त करने जा रहे हैं और अंत में प्लेलिस्ट का शीर्षक और इमेज प्रदर्शित करेंगे।
var playlist: PlayList? {
didSet {
print("Playlist ?", self.playlist)
guard let playlist = self.playlist else { return }
// The Image ?
self.ImageView.image = UIImage(named: playlist.image)
// the playlist title ?
self.TitleLabel.text = self.playlist?.title
}
}
मुझे लगता है कि सब कुछ अब ठीक काम करना चाहिए, बस नीचे की तरह ?
UI के लिए एक अंतिम अपडेट: हमें section और playlist शीर्षक में कुछ पैडिंग और मार्जिन जोड़ने होंगे और प्लेलिस्ट को थोड़ा छोटा बनाना होगा।
चलिए पहले सेक्शन शीर्षक के लिए कुछ पैडिंग जोड़ते हैं। ऐसा करने के लिए, हमें बस CustomCell के अंदर सेक्शन सेल setupSubCells के अंदर constant प्रॉपर्टी को कुछ नंबर वैल्यू देने की आवश्यकता है:
collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15).isActive = true
और यदि आप पूरे collectionView को titleLabel के नीचे आते हुए देखते हैं, तो हमें बस 15 जोड़कर अधिक स्पेस जोड़ने की आवश्यकता है:
अब हम playlist के शीर्षक पर आते हैं। यह SubCustomCell के अंदर होगा, और हमें बस ImageView के नीचे अधिक स्पेस जोड़ने की आवश्यकता है।
ImageView.bottomAnchor.constraint(equalTo: TitleLabel.topAnchor, constant: -15).isActive = true
हमारे पास पहले से ही वहां constant है। इसे काम करने के लिए, वैल्यू -15 होनी चाहिए
अंत में प्लेलिस्ट को थोड़ा छोटा होना चाहिए। यह आसान है: हम बस playlist सेल की ऊंचाई और चौड़ाई को section सेल की ऊंचाई से 2 से विभाजित करके बराबर बनाते हैं, जैसे नीचे:
CustomCell.swift
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = frame.height / 2
let height = frame.height / 2
return CGSize(width: width, height: height)
}
ImageView की ऊंचाई को भी 150 के बराबर बनाएं।
//SubCutomCell.swift
ImageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
और चलिए चलते हैं ?.
परफेक्ट! मुझे लगता कि आज के लिए इतना पर्याप्त है - मैं इस लेख को बहुत लंबा नहीं बनाना चाहता। इसलिए हमारे पास एक और भाग होगा जहां हम TabBar और विवरण जोड़ेंगे, साथ ही प्लेलिस्ट के लिए कुछ आइकन भी।
GitHub पर पूर्ण स्रोत कोड देखें?.
आपके समय के लिए धन्यवाद। मुझे आशा है कि मैंने कुछ भी मिस नहीं किया है। यदि मैंने किया तो कृपया ट्विटर पर @mention करें, या यदि आपके पास इस पोस्ट के लिए कोई प्रश्न या अतिरिक्त है तो दरवाजे हमेशा सभी के लिए खुले हैं। धन्यवाद??
सब्सक्राइब करें मेरी ईमेल सूची को ताकि जब इस ट्यूटोरियल का तीसरा भाग प्रकाशित हो तो आपको सूचित किया जाए।
वैसे, मैंने हाल ही में अपने मोबाइल एप्लिकेशन में से एक के लिए सॉफ्टवेयर इंजीनियर्स के एक मजबूत समूह के साथ काम किया है। संगठन शानदार था, और प्रोडक्ट बहुत तेजी से डिलीवर किया गया था, अन्य फर्मों और फ्रीलांसर्स की तुलना में बहुत तेज जिनके साथ मैंने काम किया है, और मुझे लगता है कि मैं उन्हें अन्य प्रोजेक्ट्स के लिए ईमानदारी से सिफारिश कर सकता हूं। अगर आप संपर्क में आना चाहते हैं तो मुझे ईमेल करें - said@devsdata.com।