使用Mapbox API创建iOS地点选择器/地点自动完成/搜索UI

尽管Mapbox不如Google受欢迎,但Mapbox提供了一个非常有用的Places API,由于Google API引入了有关其服务的计费方式,因此许多人可能会喜欢它。 Mapbox没有为Places提供iOS SDK,因此我们将使用基于其Geocoder API的端点来发出请求并获取位置。

入门

在开始之前,请在mapbox.com/signup上注册一个帐户。 在帐户页面上找到您的访问令牌。

打开信息。 plist文件和以下密钥,其值是第一步中从MapBox收到的访问令牌。

   MGLMapboxAccessToken  
YOUR_TOKEN

假设您已经创建了XCode项目,请将这些Pod添加到Podfile中。

  pod'Mapbox-iOS-SDK','〜> 4.9' 
pod'MapboxGeocoder.swift','〜> 0.10'
豆荚“ Alamofire”
pod'Alamofire-SwiftyJSON'

我们将使用Alamofire来请求对Mapbox API端点的请求,并使用SwiftyJSON来解析响应。

在您的终端中,运行“ pod install”。

设置UI

假设您已经创建了Xcode项目,请添加一个UIViewController,并确保将其嵌入在UINavigationController中,因为我们会将UISearchBar添加到导航栏中。

添加一个UITableView来完全填充视图,并在ViewController Swift类文件中为其创建出口。

导入必要的模块

 导入UIKit 
进口Alamofire
导入SwiftyJSON
导入Alamofire_SwiftyJSON

实施代表

 类PlacesSearchVC:UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate { 
覆盖func viewDidLoad(){
super.viewDidLoad()
}
}

在类内部,声明对象

  @IBOutlet var tableView:UITableView!  //向您在情节提要中创建的表格视图的出口 
var searchActive:Bool = false //用于控制搜索状态
var searchBar:UISearchBar? //要添加到导航栏中的搜索栏
var searchedPlaces:NSMutableArray = [] //用于存储响应中返回的位置的数组
letcoder = JSONDecoder()//用于解码API返回的数据

将searchBar添加到viewDidLoad()的导航栏中

 如果self.searchBar == nil { 
self.searchBar = UISearchBar()
self.searchBar!.searchBarStyle = UISearchBarStyle.prominent
self.searchBar!.tintColor = Helper.UIColorFromRGB(rgbValue:0x000000)
self.searchBar!.barTintColor = Helper.UIColorFromRGB(rgbValue:0xffffff)
self.searchBar!.delegate =自我
self.searchBar!.placeholder =“搜索位置”;
}
self.navigationItem.titleView = searchBar

创建UISearchBar的委托函数以处理事件

  func searchBarCancelButtonClicked(_ searchBar:UISearchBar){ 
自我.cancelSearching()
searchActive = false;
}

func searchBarSearchButtonClicked(_ searchBar:UISearchBar){
self.view.endEditing(true)
}

func searchBarTextDidBeginEditing(_ searchBar:UISearchBar){
self.searchBar!.setShowsCancelButton(true,动画:true)
}

func searchBarTextDidEndEditing(_ searchBar:UISearchBar){
self.searchBar!.setShowsCancelButton(false,动画:false)
}

func cancelSearching(){
searchActive = false;
self.searchBar!.resignFirstResponder()
self.searchBar!.text =“”
}

现在,让我们添加将调用搜索功能的main方法。 我们希望稍等片刻,直到用户暂停键入,然后触发该方法,然后取消所有先前可能已触发的请求。

  func searchBar(_ searchBar:UISearchBar,textDidChange searchText:String){ 
NSObject.cancelPreviousPerformRequests(withTarget:self,选择器:#selector(self.searchMe),object:nil)
self.perform(#selector(self.searchMe),带有:nil,afterDelay:0.5)
if(searchBar.text!.isEmpty){
searchActive = false;
}其他{
searchActive = true;
}
}

@objc func searchMe(){
if(searchBar?.text!.isEmpty)!{} else {
self.searchPlaces(查询:(searchBar?.text)!)
}
}

正在搜寻

为了进行搜索,请首先创建API URL。 将mapbox端点和访问令牌定义为字符串

 静态var mapbox_api =“ https://api.mapbox.com/geocoding/v5/mapbox.places/” 
静态var mapbox_access_token =“ YOUR_ACCESS_TOKEN_HERE”

创建一个新的Feature.swift类并定义响应的结构,以便我们能够直接解析响应。

 导入UIKit 

struct功能:可编码{
var id:字符串!
var类型:字符串?
var matching_place_name:字符串?
var place_name:字符串?
var geometry:Geometry
var中心:[Double]
var properties:属性
}

结构几何:可编码{
var类型:字符串?
var座标:[Double]
}

struct属性:可编码{
var地址:字符串?
}

现在创建搜索功能。

  @objc func searchPlaces(query:String){ 
让urlStr =“ \(mapbox_api)\(query).json?access_token = \(mapbox_access_token)”

Alamofire.request(urlStr,方法:.get,参数:无,编码:URLEncoding.default,标头:无).responseSwiftyJSON {(dataResponse)in

如果dataResponse.result.isSuccess {
让resJson = JSON(dataResponse.result.value!)
如果让myjson = resJson [“ features”]。array {
对于myjson中的itemobj? [] {
尝试? 打印(itemobj.rawData())
做{
让地方=尝试self.decoder.decode(Feature.self,来自:itemobj.rawData())
self.searchedPlaces.add(place)
self.tableView.reloadData()
}捕获让错误{
如果让错误=错误为? DecodingError {
打印(error.errorDescription)
}
}
}
}
}

如果dataResponse.result.isFailure {
让错误:错误= dataResponse.result.error!
}
}
}

而已! 我们已经获取了数据并进行了解析并将其保存到数组中。 现在,让我们编写代码以将其显示在表中。

在表格中显示数据

编写UITableView委托方法

  func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-> UITableViewCell { 
让单元格= UITableViewCell.init(样式:.subtitle,reuseIdentifier:“单元格”)
cell.detailTextLabel?.textColor = UIColor.darkGray

让pred = self.searchedPlaces.object(at:indexPath.row)为! 特征
cell.textLabel?.text = pred.place_name!
如果让add = pred.properties.address {
cell.detailTextLabel?.text =添加
}其他{}
cell.imageView?.image = UIImage.init(icon:.fontAwesome(.mapMarker),size:CGSize(width:30,height:30))

返回单元
}

func tableView(_ tableView:UITableView,heightForRowAt indexPath:IndexPath)-> CGFloat {
回报60.0
}

如果要从此Feature对象获取坐标,请按以下步骤操作

  func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath){ 
让cell = tableView.cellForRow(at:indexPath)
让pred = self.searchedPlaces.object(at:indexPath.row)为! 特征
让coord = CLLocationCoordinate2D.init(纬度:pred.geometry.coordinates [1],经度:pred.geometry.coordinates [0])
}