नमस्कार सभी को! इस लेख में हम सीखेंगे कि iOS ऐप्स में UISearchController का उपयोग कैसे करें।
हम क्या बनाने जा रहे हैं?
हम एक मूवी सर्च एप्लिकेशन बनाने जा रहे हैं जो TMDB API का उपयोग करके मूवी जानकारी प्राप्त करता है और उपयोगकर्ता की सर्च क्वेरी के आधार पर UICollectionView का उपयोग करके प्रदर्शित करता है।
प्रोजेक्ट सेटअप
Xcode खोलें और एक नया ब्लैंक iOS ऐप प्रोजेक्ट बनाएं - सुनिश्चित करें कि आप UIKit चुनते हैं न कि SwiftUI।
इस ऐप में हम MVC पैटर्न का उपयोग करने जा रहे हैं, इसलिए निम्नलिखित ग्रुप्स और Swift फ़ाइलें बनाकर प्रोजेक्ट को व्यवस्थित करें:
अब अपना Xcode प्रोजेक्ट बंद करें। टर्मिनल खोलें और अपने प्रोजेक्ट डायरेक्टरी में जाएं। यहां हमें मूवी पोस्टर छवियों को एसिंक्रोनसली डाउनलोड और कैश करने के लिए SD WebImage CocoaPods जोड़ने की आवश्यकता है।
टर्मिनल में निम्न कमांड टाइप करें:
pod init
अब जब आप डायरेक्टरी की सामग्री सूचीबद्ध करते हैं, तो आप देख सकते हैं कि एक नया Podfile है। किसी भी टेक्स्ट एडिटर का उपयोग करके फ़ाइल खोलें (यहां मैंने Vim का उपयोग किया है)। अपने Podfile को इस तरह संपादित करें कि यह नीचे की छवि के समान दिखे। Podfile को सेव और बंद करें।
अब जब हमने SD WebImage निर्दिष्ट कर दिया है, तो हम नीचे दी गई कमांड चलाकर निर्भरताओं को इंस्टॉल कर सकते हैं:
pod install
जैसा कि आप देख सकते हैं, हमने अपने iOS प्रोजेक्ट में SD WebImage pod को सफलतापूर्वक जोड़ लिया है। अब नीचे दी गई कमांड चलाकर अपना प्रोजेक्ट Xcode में खोलें।
open PROJECT_NAME.xcworkspace
Xcode खोलने के बाद, Command+B दबाकर अपना प्रोजेक्ट बिल्ड करना सुनिश्चित करें।
UIKit और प्रोग्रामेटिक UI का उपयोग करके यूजर इंटरफेस कैसे डिज़ाइन करें
हमारे ऐप को तीन UI एलिमेंट्स की आवश्यकता है: सर्च बार को रखने के लिए नेविगेशन बार, वास्तविक खोज के लिए UISearchController, और खोज परिणाम प्रदर्शित करने के लिए UICollectionView।
अपना SceneDelegate.swift फ़ाइल खोलें और इसमें निम्न कोड जोड़ें जो सेशन मेथड से कनेक्ट करेगा:
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 = UINavigationController(rootViewController: HomeVC())
window?.makeKeyAndVisible()
}
चूंकि हम प्रोग्रामेटिक UI का उपयोग कर रहे हैं, पहले हमें अपने रूट व्यू कंट्रोलर का उल्लेख करना होगा - यानी, पहली स्क्रीन जो उपयोगकर्ता द्वारा ऐप लॉन्च करने पर प्रदर्शित होगी।
इस ऐप में हम केवल एक व्यू कंट्रोलर का उपयोग कर रहे हैं, इसलिए हम इसे UINavigationController के अंदर लपेटते हैं। यह एक नेविगेशन बार प्रदान करता है जहां हम अपना UISearchController रख सकते हैं।
HomeVC.swift फ़ाइल खोलें और निम्न प्रॉपर्टीज जोड़ें:
private var searchBar: UISearchController = {
let sb = UISearchController()
sb.searchBar.placeholder = "मूवी का नाम दर्ज करें"
sb.searchBar.searchBarStyle = .minimal
return sb
}()
private var movieCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: UIScreen.main.bounds.width/3 - 10, height: 200)
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.register(MovieCell.self, forCellWithReuseIdentifier: MovieCell.ID)
return cv
}()
पहले हम अपना UISearchController बनाते हैं और इसकी प्रॉपर्टीज जैसे प्लेसहोल्डर टेक्स्ट और स्टाइल को कॉन्फिगर करते हैं।
फिर हम एक UICollectionView बनाते हैं और उस लेआउट के प्रकार को निर्दिष्ट करते हैं जिसका हमारे कलेक्शन व्यू को उपयोग करना चाहिए। इस मामले में यह UICollectionViewFlowLayout है और अन्य प्रॉपर्टीज जैसे स्क्रॉल दिशा, आइटम साइज, और एक कस्टम कलेक्शन व्यू सेल क्लास निर्दिष्ट करना जिसे हम बाद में अपने प्रोजेक्ट में बनाएंगे।
HomeVC क्लास के अंदर एक नया फ़ंक्शन बनाएं और हमारे UICollectionView के लिए प्रोग्रामेटिकली ऑटो-लेआउट कंस्ट्रेंट्स कॉन्फिगर करने के लिए निम्न कोड जोड़ें:
// MARK: - हेल्पर्स
func configureUI() {
movieCollectionView.translatesAutoresizingMaskIntoConstraints = false
movieCollectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
movieCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
movieCollectionView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
movieCollectionView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
}
पहले हम कहते हैं कि हमें ऑटो रिसाइजिंग मास्क को कंस्ट्रेंट्स में बदलने की आवश्यकता नहीं है। फिर हम अपने कलेक्शन व्यू को व्यू कंट्रोलर के चारों ओर पिन करते हैं।
viewDidLoad() मेथड के अंदर निम्न कोड लाइनें जोड़ें:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "मूवी सर्च"
view.backgroundColor = .systemBackground
searchBar.searchResultsUpdater = self
navigationItem.searchController = searchBar
view.addSubview(movieCollectionView)
movieCollectionView.delegate = self
movieCollectionView.dataSource = self
configureUI()
}
यहां हम पहले अपने व्यू कंट्रोलर के लिए शीर्षक निर्दिष्ट करते हैं उसके बाद बैकग्राउंड कलर जो सिस्टम बैकग्राउंड कलर है। यदि डिवाइस लाइट मोड में है तो यह सफेद बैकग्राउंड दिखाता है। यदि यह डार्क मोड में है, तो यह डार्क बैकग्राउंड दिखाता है।
फिर हम वर्तमान व्यू कंट्रोलर को सर्च रिजल्ट अपडेटर के रूप में सेट करते हैं, फिर अपने SearchController को नेविगेशन बार में जोड़ते हैं, UICollectionView को व्यू कंट्रोलर में जोड़ते हैं, और डेलीगेट और डेटासोर्स सेटअप करते हैं। अंत में हम ऑटो-लेआउट का उपयोग करके UICollectionView को पिन करते हैं।
HomeVC के लिए एक एक्सटेंशन बनाएं और UISearchResultsUpdating प्रोटोकॉल और इसके स्टब मेथड updateSearchResults को लागू करें।
extension HomeVC: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
guard let query = searchController.searchBar.text else { return }
}
}
updateSearchResults() मेथड को तब कॉल किया जाएगा जब भी सर्च बार में दर्ज टेक्स्ट बदलता है या जब उपयोगकर्ता अपने कीबोर्ड पर सर्च बटन टैप करता है।
अब हमें वह कस्टम UICollectionView सेल बनाने की आवश्यकता है। MovieCell.swift फ़ाइल के अंदर, निम्न कोड जोड़ें:
import Foundation
import UIKit
import SDWebImage
class MovieCell: UICollectionViewCell {
static let ID = "MovieCell"
private var moviePosterImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(moviePosterImageView)
configureUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) को लागू नहीं किया गया है")
}
}
extension MovieCell {
func configureUI() {
moviePosterImageView.translatesAutoresizingMaskIntoConstraints = false
moviePosterImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
moviePosterImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
moviePosterImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
moviePosterImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
}
func updateCell(posterURL: String?) {
if let posterURL = posterURL {
guard let completeURL = URL(string: "https://image.tmdb.org/t/p/w500/\(posterURL)") else { return }
self.moviePosterImageView.sd_setImage(with: completeURL)
}
}
}
यहां हम UICollectionView क्लास को सबक्लास करके और init() फ़ंक्शन को लागू करके अपना कस्टम कलेक्शन व्यू सेल बनाते हैं।
हम मूवी पोस्टर छवि प्रदर्शित करने के लिए एक UIImageView बनाते हैं और इसके लिए ऑटो-लेआउट कंस्ट्रेंट्स सेटअप करते हैं। फिर हम एक उपयोगकर्ता-परिभाषित फ़ंक्शन बनाते हैं जो मूवी पोस्टर URL स्ट्रिंग को पैरामीटर के रूप में लेता है और इसे एसिंक्रोनसली डाउनलोड करता है बिना UI थ्रेड/मेन थ्रेड को प्रभावित किए। यह SD WebImage CocoaPod का उपयोग करके करता है जिसे हमने पहले जोड़ा था।
हमारा API कैसे सेट करें
आगे बढ़ने से पहले, आपको TMDB API के लिए एक अकाउंट बनाकर (यह मुफ़्त है) अपनी API कुंजी प्राप्त करनी होगी। हम API के मूवी सर्च एंडपॉइंट का उपयोग करने जा रहे हैं जो API कुंजी और मूवी नाम को पैरामीटर के रूप में लेता है।
https://api.themoviedb.org/3/search/movie?api_key=API_KEY_HERE&query=batman
आप Postman में इसे चलाकर API प्रतिक्रिया की जांच कर सकते हैं।
API प्रतिक्रिया के लिए मॉडल कैसे बनाएं
अब हमें API से एक JSON प्रतिक्रिया मिलती है। हमें उन्हें Swift में डिकोड करने की आवश्यकता है जो हम Codable प्रोटोकॉल को लागू करने वाले एक मॉडल स्ट्रक्चर बनाकर कर सकते हैं।
हम JSON को Swift वेबसाइटों का उपयोग करके अपने JSON प्रतिक्रिया के लिए मॉडल स्ट्रक्चर आसानी से उत्पन्न कर सकते हैं। यहां API प्रतिक्रिया के लिए मॉडल कोड है - आप इसे बस कॉपी करके Model.swift फ़ाइल के अंदर पेस्ट कर सकते हैं:
import Foundation
struct TrendingTitleResponse: Codable {
let results: [Title]
}
struct Title: Codable {
let id: Int
let media_type: String?
let original_name: String?
let original_title: String?
let poster_path: String?
let overview: String?
let vote_count: Int
let release_date: String?
let vote_average: Double
}
struct YoutubeSearchResponse: Codable {
let items: [VideoElement]
}
struct VideoElement: Codable {
let id: IdVideoElement
}
struct IdVideoElement: Codable {
let kind: String
let videoId: String
}
Swift का उपयोग करके HTTP रिक्वेस्ट कैसे करें
अब हमें कुछ Swift कोड लिखने की आवश्यकता है जो HTTP GET रिक्वेस्ट करे जो API की JSON प्रतिक्रिया लौटाए।
Swift एक URLSession क्लास प्रदान करता है जो किसी थर्ड-पार्टी लाइब्रेरी जैसे AFNetworking, Alamofire, आदि की आवश्यकता के बिना नेटवर्किंग कोड लिखना आसान बनाता है।
APIService.swift खोलें और निम्न कोड जोड़ें:
import Foundation
class APIService {
static var shared = APIService()
let session = URLSession(configuration: .default)
func getMovies(for query: String, completion: @escaping ([Title]?, Error?) -> Void) {
guard let formattedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else { return }
guard let searchURL = URL(string: "https://api.themoviedb.org/3/search/movie?api_key=API_KEY_HERE&query=\(formattedQuery)") else {
print("अमान्य")
return
}
let task = session.dataTask(with: searchURL) { data, response, error in
if let error = error {
print(error.localizedDescription)
completion(nil, error)
}
if let data = data {
do {
let decodedData = try JSONDecoder().decode(TrendingTitleResponse.self, from: data)
completion(decodedData.results, nil)
} catch {
print(error)
}
}
}
task.resume()
}
}
यहां हमने सिंगलटन पैटर्न के साथ APIService नामक एक क्लास बनाई इसलिए हमें इस क्लास के एक इंस्टेंस की आवश्यकता है जो क्लास के स्टैटिक मेंबर के रूप में हो। फिर हमने डिफ़ॉल्ट कॉन्फिगरेशन के साथ अपने नेटवर्किंग टास्क के लिए एक सेशन बनाया, उसके बाद एक उपयोगकर्ता-परिभाषित मेथड getMovies()।
फिर हमने अपना नेटवर्किंग टास्क बनाया - इस मामले में हमें HTTP GET रिक्वेस्ट करने की आवश्यकता है जिसे URLSession क्लास के dataTask() मेथड का उपयोग करके किया जा सकता है। यह URL को पैरामीटर के रूप में लेता है और एक कम्पलीशन हैंडलर देता है जिसमें API से लौटाया गया डेटा, यदि कोई त्रुटि हुई तो त्रुटि डेटा, और एक प्रतिक्रिया जिसमें HTTP प्रतिक्रिया जानकारी जैसे स्टेटस कोड और उनके संबंधित संदेश होते हैं।
यदि कोई त्रुटि है, तो हम त्रुटि डेटा के साथ इस फ़ंक्शन से बाहर निकलते हैं। यदि नहीं, तो हम अपने Swift मॉडल के आधार पर अपने JSON डेटा को डिकोड करते हैं और डिकोडेड डेटा के साथ इस फ़ंक्शन से बाहर निकलते हैं।
UICollectionView पर खोज परिणाम कैसे प्रदर्शित करें
HomeVC.swift में, एक प्राइवेट प्रॉपर्टी बनाएं जो Title ऑब्जेक्ट्स की एक सरणी है। ये API द्वारा लौटाई गई प्रत्येक मूवी की जानकारी को रखेंगे।
private var movies = [Title]()
HomeVC.swift में HomeVC क्लास के लिए एक एक्सटेंशन बनाएं और UICollectionViewDelegate और UICollectionViewDataSource प्रोटोकॉल को लागू करें। फिर numberOfItemsInSection (जो API द्वारा लौटाई गई फिल्मों की संख्या के बराबर है) और cellForItemAt (जो वास्तव में API प्रतिक्रियाओं के साथ सेल को पॉप्युलेट करता है, जैसे पोस्टर छवि डाउनलोड और सेट करना) को लागू करें।
extension HomeVC: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return movies.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MovieCell.ID, for: indexPath) as? MovieCell {
cell.updateCell(posterURL: movies[indexPath.row].poster_path)
return cell
}
return UICollectionViewCell()
}
}
अंत में हमें वास्तविक API कॉल करने की आवश्यकता है जो हम पहले लागू किए गए updateSearchResults() डेलीगेट मेथड के अंदर करते हैं। उस मेथड के अंदर निम्न कोड जोड़ें:
func updateSearchResults(for searchController: UISearchController) {
guard let query = searchController.searchBar.text else { return }
APIService.shared.getMovies(for: query.trimmingCharacters(in: .whitespaces)) { titles, error in
if let titles = titles {
self.movies = titles
DispatchQueue.main.async {
self.movieCollectionView.reloadData()
}
}
}
}
यहां, जब भी उपयोगकर्ता सर्च बार में टाइप करता है या सर्च बटन दबाता है, हम सर्च बार में दर्ज नाम के आधार पर मूवी लाने के लिए एक HTTP GET रिक्वेस्ट करते हैं। फिर हम कलेक्शन व्यू को रीलोड करते हैं जो कलेक्शन व्यू सेल्स को मूवी पोस्टर के साथ अपडेट करता है।
ध्यान दें कि हमें इसे मेन थ्रेड/UI थ्रेड में करने की आवश्यकता है, क्योंकि डिफ़ॉल्ट रूप से iOS स्वचालित रूप से HTTP रिक्वेस्ट को बैकग्राउंड थ्रेड में करता है। इसका मतलब है कि हमें अपने UI एलिमेंट्स को अपडेट करने के लिए UI/मेन थ्रेड का उपयोग करने की आवश्यकता है।
अब सिम्युलेटर में अपना ऐप चलाकर परिणाम देखें:
बधाई हो! आपने iOS ऐप्स में UISearchController का उपयोग करना सीख लिया।