सभी को नमस्कार! इस लेख में हम सीखेंगे कि iOS ऐप्स में UISearchController का उपयोग कैसे करें।
हम क्या बनाने जा रहे हैं?
हम एक मूवी खोज एप्लिकेशन बनाने जा रहे हैं जो मूवी जानकारी प्राप्त करने के लिए TMDB API का उपयोग करता है और उपयोगकर्ता की खोज क्वेरी के आधार पर UICollectionView का उपयोग करके इसे प्रदर्शित करता है।
प्रोजेक्ट सेटअप
Xcode खोलें और एक नया रिक्त iOS ऐप प्रोजेक्ट बनाएं - सुनिश्चित करें कि आपने UIKit का चयन किया है न कि SwiftUI का।
इस ऐप में हम एमवीसी पैटर्न का उपयोग करने जा रहे हैं इसलिए निम्नलिखित समूह और स्विफ्ट फाइलें बनाकर परियोजना को व्यवस्थित करें:
अब अपना Xcode प्रोजेक्ट बंद करें। टर्मिनल खोलें और अपनी परियोजना निर्देशिका में जाएँ। यहां हमें मूवी पोस्टर छवियों को एसिंक्रोनस रूप से डाउनलोड और कैश करने के लिए एसडी वेबइमेज कोको पॉड्स जोड़ने की जरूरत है।
टर्मिनल में निम्न कमांड टाइप करें:
pod init
अब जब आप निर्देशिका की सामग्री को सूचीबद्ध करते हैं, तो आप देख सकते हैं कि एक नया पॉडफाइल है। किसी भी टेक्स्ट एडिटर का उपयोग करके फ़ाइल खोलें (यहां मैंने विम का उपयोग किया है)। अपने पॉडफाइल को संपादित करें ताकि यह नीचे की छवि के समान दिखे। पॉडफाइल को सेव और बंद करें।
अब जब हमने SD WebImage निर्दिष्ट कर दिया है, तो हम नीचे दिए गए आदेश को चलाकर निर्भरताएँ स्थापित कर सकते हैं:
pod install
जैसा कि आप देख सकते हैं, हमने अपने iOS प्रोजेक्ट में SD WebImage पॉड को सफलतापूर्वक जोड़ा है। अब हमारे प्रोजेक्ट को Xcode में खोलने के लिए निम्न कमांड चलाएँ।
open PROJECT_NAME.xcworkspace
Xcode खोलने के बाद, सुनिश्चित करें कि आपने Command+B मार कर अपना प्रोजेक्ट बनाया है।
UIKit और प्रोग्रामेटिक UI का उपयोग करके उपयोगकर्ता इंटरफ़ेस कैसे डिज़ाइन करें
हमारे ऐप को सर्च बार को होल्ड करने के लिए तीन UIElements नेविगेशन बार, वास्तविक सर्च के लिए UISearchBarController और सर्च रिजल्ट्स को प्रदर्शित करने के लिए एक UICollectionView की आवश्यकता है।
अपनी Scnedelegate.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()
}
चूंकि हम एक प्रोग्रामिक यूआई का उपयोग कर रहे हैं, पहले हमें अपने रूट व्यू कंट्रोलर का उल्लेख करना होगा - यानी, पहली स्क्रीन जो उपयोगकर्ता द्वारा ऐप लॉन्च करने पर प्रदर्शित होगी।
यहां इस ऐप में हम केवल एक व्यू कंट्रोलर का उपयोग कर रहे हैं, इसलिए हम इसे UINavigationController के अंदर लपेटते हैं। यह एक नेविगेशन बार प्रदान करता है जहां हम अपना UISearchController रख सकते हैं।
HomeVC.swift फ़ाइल खोलें और निम्नलिखित गुण जोड़ें:
private var SearchBar: UISearchController = {
let sb = UISearchController()
sb.searchBar.placeholder = "Enter the movie name"
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 और अन्य गुण हैं जैसे स्क्रॉल दिशा, आइटम का आकार, और एक कस्टम CollectionView सेल वर्ग निर्दिष्ट करना जिसे हम बाद में अपने प्रोजेक्ट में बनाएंगे।
HomeVC वर्ग के अंदर एक नया फ़ंक्शन बनाएं और हमारे UICollectionView के लिए प्रोग्रामेटिक रूप से ऑटो-लेआउट बाधाओं को कॉन्फ़िगर करने के लिए निम्न कोड जोड़ें:
//MARK: - HELPERS
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 = "Movie Search"
view.backgroundColor = .systemBackground
SearchBar.searchResultsUpdater = self
navigationItem.searchController = SearchBar
view.addSubview(MovieCollectionView)
MovieCollectionView.delegate = self
MovieCollectionView.dataSource = self
configureUI()
}
यहां हम पहले अपने व्यू कंट्रोलर के लिए शीर्षक निर्दिष्ट करते हैं, उसके बाद बैकग्राउंड कलर जो कि सिस्टमबैकग्राउंड कलर है। यदि डिवाइस लाइट मोड में है तो यह एक सफेद बैकग्राउंड दिखाता है। अगर यह डार्क मोड में है तो यह डार्क बैकग्राउंड दिखाता है।
फिर हम व्यू कंट्रोलर को सर्च रिजल्ट अपडेटर के रूप में सेट करते हैं, फिर नेविगेशन बार में अपना सर्च कंट्रोलर जोड़ते हैं, व्यू कंट्रोलर में UICollectionView जोड़ते हैं, और प्रतिनिधि और डेटासोर्स सेट करते हैं। अंत में हम ऑटो-लेआउट का उपयोग करके UICollectionView को पिन करते हैं।
HomeVC के लिए एक एक्सटेंशन बनाएं और UISearchResultsUpdating प्रोटोकॉल और उसकी स्टब विधि अपडेटSearchResults लागू करें।
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
// imageView.image = UIImage(systemName: "house")
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(MoviePosterImageView)
configureUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
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 बनाते हैं। फिर हम एक उपयोगकर्ता परिभाषित फ़ंक्शन बनाते हैं जो मूवी पोस्टर यूआरएल स्ट्रिंग को एक पैरामीटर लेता है और यूआई थ्रेड/मुख्य थ्रेड को प्रभावित किए बिना इसे असीमित रूप से डाउनलोड करता है। यह SD WebImage CocoaPod का उपयोग करके ऐसा करता है जिसे हमने पहले जोड़ा था।
हमारा एपीआई कैसे सेट करें
आगे बढ़ने से पहले, आपको एक खाता बनाकर TMDB API के लिए अपनी API कुंजी प्राप्त करनी होगी (यह मुफ़्त है)। हम एपीआई के मूवी सर्च एंड पॉइंट का उपयोग करने जा रहे हैं जो एपीआई कुंजी और मूवी नाम को पैरामीटर के रूप में लेता है।
https://api.themoviedb.org/3/search/movie?api_key=API_KEY_HERE&query=batman
आप एपीआई प्रतिक्रिया को पोस्टमैन में चलाकर जांच सकते हैं।
एपीआई प्रतिक्रिया के लिए एक मॉडल कैसे बनाएं
अब हमें एपीआई से JSON रिस्पांस मिलता है। हमें उन्हें स्विफ्ट में डिकोड करने की आवश्यकता है जो हम कोडेबल प्रोटोकॉल को लागू करने वाली मॉडल संरचना बनाकर कर सकते हैं।
हम JSON से स्विफ्ट वेबसाइटों का उपयोग करके आसानी से हमारे JSON प्रतिक्रिया के लिए मॉडल संरचना उत्पन्न कर सकते हैं। यहाँ एपीआई प्रतिक्रिया के लिए मॉडल कोड है - आप इसे 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
}
स्विफ्ट का उपयोग करके HTTP अनुरोध कैसे निष्पादित करें
अब हमें HTTP GET अनुरोध करने के लिए कुछ स्विफ्ट कोड लिखने की आवश्यकता है जो API की JSON प्रतिक्रिया लौटाते हैं।
स्विफ्ट एक 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 FormatedQuery = Query.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else{return}
guard let SEARCH_URL = URL(string: "https://api.themoviedb.org/3/search/movie?api_key=API_KEY_HERE&query=\(FormatedQuery)") else {print("INVALID")
return}
let task = session.dataTask(with: SEARCH_URL) { 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)
// print(decodedData)
completion(decodedData.results,nil)
}
catch{
print(error)
}
}
}
task.resume()
}
}
यहां हमने सिंगलटन पैटर्न के साथ एपीआई सेवा नामक एक वर्ग बनाया है, इसलिए हमें इस वर्ग के लिए कक्षा के स्थिर सदस्य के रूप में एक उदाहरण की आवश्यकता है। फिर हमने अपने नेटवर्किंग कार्य के लिए डिफ़ॉल्ट कॉन्फ़िगरेशन के साथ एक सत्र बनाया, उसके बाद एक उपयोगकर्ता परिभाषित विधि getMovies ()।
फिर हमने अपना नेटवर्किंग कार्य बनाया - इस मामले में हमें HTTP GET अनुरोध करने की आवश्यकता है जो कि dataTask()
का उपयोग करके किया जा सकता है URLSession वर्ग की विधि। यह URL को एक पैरामीटर के रूप में लेता है और एक पूर्णता हैंडलर देता है जिसमें API से लौटाया गया डेटा होता है, यदि कोई त्रुटि हुई है तो त्रुटि डेटा, और एक प्रतिक्रिया जिसमें HTTP प्रतिक्रिया जानकारी जैसे स्थिति कोड और उनके संबंधित संदेश होते हैं।
यदि कोई त्रुटि है, तो हम त्रुटि डेटा के साथ इस फ़ंक्शन से बाहर निकल जाते हैं। यदि नहीं, तो हम अपने स्विफ्ट मॉडल के आधार पर अपने JSON डेटा को डिकोड करते हैं और डिकोड किए गए डेटा के साथ इस फ़ंक्शन से बाहर निकलते हैं।
UICollectionView पर खोज परिणाम कैसे प्रदर्शित करें
HomeVC.swift में, एक निजी संपत्ति बनाएं जो शीर्षक वस्तुओं की एक सरणी है। ये एपीआई द्वारा लौटाई गई प्रत्येक फिल्म की जानकारी रखेंगे।
private var Movies = [Title]()
HomeVC.swift में HomeVC वर्ग के लिए एक एक्सटेंशन बनाएं और UIColletionViewDelegate और UICollectionViewDatasource प्रोटोकॉल लागू करें। फिर numberOfItemsInSection (जो कि एपीआई द्वारा लौटाई गई फिल्मों की संख्या के बराबर है) और सेलफोरइटमएट (जो वास्तव में एपीआई प्रतिक्रियाओं के साथ सेल को पॉप्युलेट करता है, जैसे पोस्टर छवि को डाउनलोड और सेट करता है) को लागू करें।
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.backgroundColor = .systemBackground
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 अनुरोध करते हैं (खोज बार में दर्ज नाम के आधार पर)। फिर हम कलेक्शन व्यू को फिर से लोड करते हैं जो मूवी पोस्टर के साथ कलेक्शन व्यू सेल को अपडेट करता है।
ध्यान दें कि हमें इसे मुख्य थ्रेड/यूआई थ्रेड में करने की ज़रूरत है, क्योंकि डिफ़ॉल्ट रूप से आईओएस स्वचालित रूप से पृष्ठभूमि थ्रेड में HTTP अनुरोध करता है। इसका मतलब है कि हमें अपने UI तत्वों को अपडेट करने के लिए UI/Main Thread का उपयोग करने की आवश्यकता है।
अब परिणाम देखने के लिए सिम्युलेटर में अपना ऐप चलाएं:
बधाई हो! आपने iOS ऐप्स में UISearchController का उपयोग करना सीख लिया है।