iPhone
 Computer >> コンピューター >  >> スマートフォン >> iPhone

iOS アプリで UISearchController を使用する方法

こんにちは、みんな!この記事では、iOS アプリで UISearchController を使用する方法を学びます。

何を構築しますか?

TMDB API を使用して映画情報を取得し、ユーザーの検索クエリに基づいて UICollectionView を使用して表示する映画検索アプリケーションを作成します。

プロジェクトのセットアップ

Xcode を開き、新しい空白の iOS アプリ プロジェクトを作成します。SwiftUI ではなく、必ず UIKit を選択してください。

このアプリでは MVC パターンを使用するため、次のグループと Swift ファイルを作成してプロジェクトを編成します:

iOS アプリで UISearchController を使用する方法

Xcode プロジェクトを閉じます。ターミナルを開き、プロジェクト ディレクトリに移動します。ここでは、SD WebImage Cocoa Pod を追加して、映画のポスター画像を非同期にダウンロードしてキャッシュする必要があります。

ターミナルに次のコマンドを入力してください:

pod init

ディレクトリの内容を一覧表示すると、新しい Podfile があることがわかります。任意のテキスト エディターを使用してファイルを開きます (ここでは Vim を使用しました)。下の画像のようになるように Podfile を編集します。 Podfile を保存して閉じます。

iOS アプリで UISearchController を使用する方法

SD WebImage を指定したので、以下のコマンドを実行して依存関係をインストールできます:

pod install

ご覧のとおり、SD WebImage ポッドが iOS プロジェクトに正常に追加されました。以下のコマンドを実行して、Xcode でプロジェクトを開きます。

open PROJECT_NAME.xcworkspace

Xcode を開いた後、必ず Command+B を押してプロジェクトをビルドしてください。

UIKit とプログラム UI を使用してユーザー インターフェースを設計する方法

このアプリには、検索バーを保持するための 3 つの UIElements ナビゲーション バー、実際の検索のための UISearchBarController、および検索結果を表示するための 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 を使用しているため、最初にルート ビュー コントローラー (つまり、ユーザーがアプリを起動したときに表示される最初の画面) について言及する必要があります。

このアプリでは、View Controller を 1 つだけ使用しているため、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
    }

まず、自動サイズ変更マスクを制約に変換する必要はないと言います。次に、View Controller の 4 つの側面すべてにコレクション ビューをピン留めします。

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

ここでは、最初に ViewController のタイトルを指定し、続いて systemBackground 色である背景色を指定します。デバイスがライト モードの場合、白い背景が表示されます。ダーク モードの場合は、暗い背景が表示されます。

次に、現在のビュー コントローラーを検索結果アップデーターとして設定し、SearchController をナビゲーション バーに追加し、UICollectionView を ViewController に追加し、デリゲートとデータソースをセットアップします。最後に、自動レイアウトを使用して 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
      //  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 を作成し、自動レイアウト制約を設定します。次に、映画ポスターの 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 応答を調べることができます。

iOS アプリで UISearchController を使用する方法

API レスポンスのモデルを作成する方法

これで、API から JSON 応答を取得できます。 Codable プロトコルを実装するモデル構造体を作成することで、それらを Swift にデコードする必要があります。

JSON to Swift Web サイトを使用して、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 リクエストを実行する方法

ここで、API の JSON 応答を返す HTTP GET 要求を実行する Swift コードを記述する必要があります。

Swift は、AFNetworking、AlamoFire などのサードパーティ ライブラリを必要とせずにネットワーク コードを簡単に記述できるようにする URLSession クラスを提供します。

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

ここでは、シングルトン パターンを使用して API Service という名前のクラスを作成したため、このクラスのインスタンスがクラスの静的メンバーとして必要です。次に、ネットワーク タスクのセッションをデフォルトの構成で作成し、続いてユーザー定義メソッド getMovies() を作成しました。

次に、ネットワーク タスクを作成しました。この場合、dataTask() を使用して実行できる HTTP GET 要求を実行する必要があります。 URLSession クラスのメソッド。 URL をパラメーターとして受け取り、API から返されたデータ、エラーが発生した場合のエラー データ、およびステータス コードとそれに対応するメッセージなどの HTTP 応答情報を含む応答を含む完了ハンドラーを提供します。

エラーが発生した場合は、エラー データを使用してこの関数をエスケープします。そうでない場合は、Swift モデルに基づいて JSON データをデコードし、デコードされたデータでこの関数をエスケープします。

UICollectionView で検索結果を表示する方法

HomeVC.swift で、Title オブジェクトの配列であるプライベート プロパティを作成します。これらは、API によって返された各映画の情報を保持します。

private var Movies = [Title]()

HomeVC.swift で、HomeVC クラスの拡張機能を作成し、UIColletionViewDelegate および UICollectionViewDatasource プロトコルを実装します。次に、numberOfItemsInSection (API によって返される映画の数に等しい) と cellForItemAt (ダウンロードやポスター画像の設定など、実際にセルに API 応答を入力します) を実装します。

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

最後に、updateSearchResults() 内で実際の API 呼び出しを行う必要があります。 以前に実装したデリゲート メソッド。そのメソッド内に次のコードを追加します:

    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 要求を行います。次に、CollectionView をリロードして、コレクション ビューのセルを映画のポスターで更新します。

メイン スレッド/UI スレッドでこれを行う必要があることに注意してください。デフォルトでは、iOS はバックグラウンド スレッドで HTTP リクエストを自動的に作成するためです。これは、UI/メイン スレッドを使用して UI 要素を更新する必要があることを意味します。

シミュレーターでアプリを実行して結果を確認します。

iOS アプリで UISearchController を使用する方法

おめでとう! iOS アプリで UISearchController を使用する方法を学習しました。


  1. iOS 11 でポッドキャスト アプリを使用する方法

    Apple はついに、自社の Podcast アプリを一新する必要があることに気づき、iOS 11 によって新しい命が吹き込まれました。待望のアプリのビジュアル アップデートは魅力的で、ポッドキャストを簡単に追加して聞くことができます。さらに、これに加えて、あなたの好みを知るようになると、いくつかのポッドキャストもお勧めします.新機能は作成者とユーザーの両方を対象としています。 革新的なタブのデザイン アプリを起動して最初に気付くのは、アプリの下部に追加された 4 つの新しいタブです。 4 つのタブは、Listen Now、Library、Browse、Search です。 [検索] タブに

  2. iOS 11 で Airdrop を使用する方法

    Airdropは、iPhone に組み込まれた素晴らしいファイル共有アプリです。 2 つの Apple デバイス間でファイルをすばやく共有できます。写真、Safari、連絡先からエアドロップを使用できます。 iOS 10までAirdropボタンはコントロールセンターに表示されていましたが、iOS11ではコントロールセンターに表示されません.この記事では、iOS 11 で Airdrop を有効または無効にする方法と、iPhone で Airdrop を使用してファイルを共有する方法について説明します。 iOS 11 での Airdrop の有効化と無効化: iOS 11 で Airdrop を