简体   繁体   English

如何在 Swift 中添加搜索栏?

[英]How to add a Search Bar in Swift?

I'm trying to add a search bar in this pokedex.我正在尝试在此图鉴中添加一个搜索栏。 I want to add a search bar which filters out data when typed.我想添加一个搜索栏,在输入时过滤掉数据。 The search bar doesn't filter out data when typed.搜索栏在键入时不会过滤掉数据。 I'm new to programming so really not sure where I'm wrong.我是编程新手,所以真的不确定我错在哪里。 Any help would be much appreciated.任何帮助将非常感激。 Here's my code这是我的代码

import UIKit

class PokemonListViewController: UITableViewController, UISearchBarDelegate {
    
    @IBOutlet var searchBar: UISearchBar!
    var pokemon: [PokemonListResult] = []
    var filteredData: [PokemonListResult] = []
    var pokeSearch = false
    
    func capitalize(text: String) -> String {
        return text.prefix(1).uppercased() + text.dropFirst()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        searchBar.delegate = self
        
        guard let url = URL(string: "https://pokeapi.co/api/v2/pokemon?limit=151") else {
            return
        }
        
        URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let data = data else {
                return
            }
            
            do {
                let entries = try JSONDecoder().decode(PokemonListResults.self, from: data)
                self.pokemon = entries.results
                self.filteredData = self.pokemon
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            }
            catch let error {
                print(error)
            }
        }.resume()
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if pokeSearch {
            return filteredData.count
        } else {
            return pokemon.count
        }
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "PokemonCell", for: indexPath)
        if pokeSearch {
            cell.textLabel?.text = capitalize(text: filteredData[indexPath.row].name)
        } else {
            cell.textLabel?.text = capitalize(text: pokemon[indexPath.row].name)
        }
        return cell
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "ShowPokemonSegue",
                let destination = segue.destination as? PokemonViewController,
                let index = tableView.indexPathForSelectedRow?.row {
            destination.url = pokemon[index].url
        }
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        if searchBar.text == " " || searchBar.text == nil {
            pokeSearch = false
            tableView.reloadData()
        } else {
            
            //let lower = searchBar.text!.lowercased()
            
            //filteredData = pokemon.filter({$0.name.range(of: lower) != nil})
            filteredData = pokemon.filter({pokemon -> Bool in
                pokemon.name.contains(searchText)
            })
            pokeSearch = true
                       
            tableView.reloadData()
            
        }
    }
}

}

PokemonViewController口袋妖怪视图控制器

import UIKit导入 UIKit

class PokemonViewController: UIViewController { var url: String! class PokemonViewController: UIViewController { var url: String!

@IBOutlet var nameLabel: UILabel!
@IBOutlet var numberLabel: UILabel!
@IBOutlet var type1Label: UILabel!
@IBOutlet var type2Label: UILabel!

func capitalize(text: String) -> String {
    return text.prefix(1).uppercased() + text.dropFirst()
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    nameLabel.text = ""
    numberLabel.text = ""
    type1Label.text = ""
    type2Label.text = ""

    loadPokemon()
}

func loadPokemon() {
    URLSession.shared.dataTask(with: URL(string: url)!) { (data, response, error) in
        guard let data = data else {
            return
        }

        do {
            let result = try JSONDecoder().decode(PokemonResult.self, from: data)
            DispatchQueue.main.async {
                self.navigationItem.title = self.capitalize(text: result.name)
                self.nameLabel.text = self.capitalize(text: result.name)
                self.numberLabel.text = String(format: "#%03d", result.id)

                for typeEntry in result.types {
                    if typeEntry.slot == 1 {
                        self.type1Label.text = typeEntry.type.name
                    }
                    else if typeEntry.slot == 2 {
                        self.type2Label.text = typeEntry.type.name
                    }
                }
            }
        }
        catch let error {
            print(error)
        }
    }.resume()
}

} }

Pokemon

import Foundation

struct PokemonListResults: Codable {
    let results: [PokemonListResult]
}

struct PokemonListResult: Codable {
    let name: String
    let url: String
}

struct PokemonResult: Codable {
    let id: Int
    let name: String
    let types: [PokemonTypeEntry]
}

struct PokemonTypeEntry: Codable {
    let slot: Int
    let type: PokemonType
}

struct PokemonType: Codable {
    let name: String
}

The logic is fine, but you accidentally put the textDidChange delegate method inside the prepare method, so that it does not get called:逻辑很好,但你不小心把textDidChange委托方法放在prepare方法中,这样它就不会被调用:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "ShowPokemonSegue",
                let destination = segue.destination as? PokemonViewController,
                let index = tableView.indexPathForSelectedRow?.row {
            destination.url = pokemon[index].url
        } //HERE -> this closes the if-statement, not the method !!
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

Just fix the curly braces.只需修复花括号。 Also, note two things:另外,请注意两点:

  • filteredData variable contains Pokemon names which are lowercased (eg blastoise) so typing B will not reveal any results; filteredData 变量包含小写的口袋妖怪名称(例如blastoise),因此输入B不会显示任何结果; you should adjust the logic here according to your needs你应该根据你的需要调整这里的逻辑
  • you can consider trimming whitespaces in the text like let searchBarText = searchBar.text?.trimmingCharacters(in: .whitespacesAndNewlines) and then checking if searchBarText == "" { //... } else {...} to get rid of empty inputs and reload the data when cleared using the search bar's x button您可以考虑修剪文本中的空格,例如let searchBarText = searchBar.text?.trimmingCharacters(in: .whitespacesAndNewlines)然后检查if searchBarText == "" { //... } else {...}以摆脱清空输入并在使用搜索栏的x按钮清除时重新加载数据

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM