我非常喜欢iOS 11.0附带的UISearchBar的新设计。我想在我自己的应用程序中包含一个搜索栏。 该应用程序包含一个导航控制器。我试图在我的一个UITableViewController实例上包含搜索栏。
这是棘手的部分。只要搜索字段处于活动状态(即是第一个响应者),我就无法导航表视图。当我点击"搜索"键盘上的按钮,键盘按预期消失,但UITableView仍然没有响应。常规行为已经恢复"一旦我点击了UItableView。但随后UISearchBar文本被重置为空字符串(不是由我)。我错过了什么吗?我很确定所有内容都已正确连接。
以下是完整代码:
class StravaSelectionViewController : UITableViewController,
UISearchBarDelegate, MKMapViewDelegate
{
private let searchController = UISearchController(searchResultsController: nil)
private var allActivities: [ActivitySummary] = []
private var allRoutes: [RouteSummary] = []
private var allSegments: [SegmentSummary] = []
private var activities: [ActivitySummary] = []
private var routes: [RouteSummary] = []
private var segments: [SegmentSummary] = []
var mode: StravaLoadMode = .none
var activitySelected: ((ActivitySummary) -> ())?
var segmentSelected: ((SegmentSummary) -> ())?
var routeSelected: ((RouteSummary) -> ())?
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.tableFooterView = UIView()
self.initSearchBar()
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
self.refresh()
}
override func viewDidDisappear(_ animated: Bool)
{
super.viewDidAppear(animated)
self.allActivities.removeAll()
self.allRoutes.removeAll()
self.allSegments.removeAll()
self.activities.removeAll()
self.routes.removeAll()
self.segments.removeAll()
}
fileprivate func initSearchBar()
{
self.definesPresentationContext = true
self.searchController.searchBar.delegate = self
self.searchController.searchBar.placeholder = Resources.SEARCH_PLACEHOLDER
self.searchController.searchBar.showsScopeBar = false
self.navigationItem.searchController = searchController
self.navigationItem.searchController?.searchBar.tintColor = UIColor.white
}
// MARK: Refresh
fileprivate func refresh()
{
switch self.mode
{
case .activities:
self.loadActivities()
break
case .routes:
self.loadRoutes()
break
case .segments:
self.loadSegments()
break
default:
break
}
}
fileprivate func loadActivities()
{
Indicator.shared.present(self, Resources.LOADING_ACTIVITIES, true)
let client: ActivityClient = ActivityClient()
client.getActivities(1, 200)
{
activities in
self.allActivities.append(contentsOf: activities)
self.activities.append(contentsOf: activities)
DispatchQueue.main.async
{
self.tableView.reloadData()
Indicator.shared.dismiss(true)
}
}
}
fileprivate func loadRoutes()
{
guard let athleteId = Settings.getAthleteId() else { return }
Indicator.shared.present(self, Resources.LOADING_ROUTES, true)
let client = RouteClient()
client.getRoutes(athleteId)
{
routes in
self.routes.append(contentsOf: routes)
self.allRoutes.append(contentsOf: routes)
DispatchQueue.main.async
{
self.tableView.reloadData()
Indicator.shared.dismiss(true)
}
}
}
fileprivate func loadSegments()
{
Indicator.shared.present(self, Resources.LOADING_SEGMENTS, true)
let client = SegmentClient()
client.getAllStarredSegments(page: 1)
{
segments, finished in
if let segments = segments
{
self.segments.append(contentsOf: segments)
self.allSegments.append(contentsOf: segments)
}
if finished == true
{
// Sort the segments alphabetically
self.segments.sort{ $0.name < $1.name }
self.allSegments.sort{ $0.name < $1.name }
DispatchQueue.main.async
{
self.tableView.reloadData()
Indicator.shared.dismiss(true)
}
}
}
}
// MARK: Table View
override func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
switch mode
{
case .activities:
return self.activities.count
case .routes:
return self.routes.count
case .segments:
return self.segments.count
default:
return 0
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
switch mode
{
case .activities:
return self.fillActivityCell(row: indexPath.row)
case .routes:
return self.fillRouteCell(row: indexPath.row)
case .segments:
return self.fillSegmentCell(row: indexPath.row)
default:
return UITableViewCell()
}
}
fileprivate func fillActivityCell(row: Int) -> ActivityCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "activityCell") as! ActivityCell
let activity = self.activities[row]
cell.activity = activity
cell.route = nil
cell.segment = nil
cell.name.text = activity.name
if let distance = activity.distance
{
cell.distance.text = Utilities.getUnitDistance(distance.floatValue)
}
if let elevation = activity.elevationGain
{
cell.elevation.text = Utilities.getUnitElevation(elevation.intValue)
}
// Map
if let map = activity.map
{
if let summary = map.summary
{
var coordinates = PolylineDecoder.decode(summary)
DispatchQueue.main.async
{
cell.map.layer.cornerRadius = 10.0
// Clear old overlays
cell.map.removeOverlays(cell.map.overlays)
cell.map.delegate = self
let polyline = MKPolyline(coordinates: &coordinates, count: coordinates.count)
cell.map.add(polyline)
cell.map.setRegion(MKCoordinateRegionForMapRect(polyline.boundingMapRect), animated: false)
}
}
}
return cell
}
fileprivate func fillRouteCell(row: Int) -> ActivityCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "activityCell") as! ActivityCell
let route = self.routes[row]
cell.route = route
cell.activity = nil
cell.segment = nil
cell.name.text = route.name
if let distance = route.distance
{
cell.distance.text = Utilities.getUnitDistance(distance.floatValue)
}
if let elevation = route.elevationGain
{
cell.elevation.text = Utilities.getUnitElevation(elevation.intValue)
}
// Map
if let map = route.map
{
if let summary = map.summary
{
var coordinates = PolylineDecoder.decode(summary)
DispatchQueue.main.async
{
cell.map.layer.cornerRadius = 8.0
// Clear old overlays
cell.map.removeOverlays(cell.map.overlays)
cell.map.delegate = self
let polyline = MKPolyline(coordinates: &coordinates, count: coordinates.count)
cell.map.add(polyline)
cell.map.setRegion(MKCoordinateRegionForMapRect(polyline.boundingMapRect), animated: false)
}
}
}
return cell
}
fileprivate func fillSegmentCell(row: Int) -> SegmentCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "segmentCell") as! SegmentCell
let segment = self.segments[row]
cell.name.text = segment.name
if let distance = segment.distance
{
cell.distance.text = Utilities.getUnitDistance(distance.floatValue)
}
if let city = segment.city, let state = segment.state, let country = segment.country
{
cell.location.text = String(format: "%@, %@, %@", city, state, country)
}
if let grade = segment.averageGrade
{
cell.averageGrade.text = String(format: "%.2f %%", grade.floatValue)
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
switch mode
{
case .activities:
self.activitySelected?(self.activities[indexPath.row])
break
case .segments:
self.segmentSelected?(self.segments[indexPath.row])
break
case .routes:
self.routeSelected?(self.routes[indexPath.row])
break
case .none:
break
}
DispatchQueue.main.async
{
self.navigationController?.popToRootViewController(animated: true)
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if mode == .segments
{
return 80.0
}
return 256.0
}
// MARK: Map
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
{
let polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.red
polylineRenderer.lineWidth = 1
return polylineRenderer
}
// MARK: Selection Color
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
let selectionView = UIView()
selectionView.backgroundColor = UIColor(r: 40.0, g: 40.0, b: 40.0, alpha: 1.0)
cell.selectedBackgroundView = selectionView
}
// MARK: Search
private var searchBarIsEmpty: Bool
{
get { return searchController.searchBar.text?.isEmpty ?? true }
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
{
self.resetSearch()
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
Swift.print("Search clicked")
self.searchController.searchBar.endEditing(true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
self.filter(searchText)
self.tableView.reloadData()
}
fileprivate func filter(_ searchText: String)
{
if searchText.isEmpty
{
self.resetSearch()
}
else
{
let search = searchText.lowercased()
switch self.mode
{
case .activities:
self.filterActivities(search)
break
case .routes:
self.filterRoutes(search)
break
case .segments:
self.filterSegments(search)
break
default:
break
}
}
}
fileprivate func filterSegments(_ search: String)
{
self.segments = self.allSegments.filter({ $0.name.lowercased().contains(search) })
}
fileprivate func filterRoutes(_ search: String)
{
self.routes = self.allRoutes.filter({ $0.name.lowercased().contains(search) })
}
fileprivate func filterActivities(_ search: String)
{
self.activities = self.allActivities.filter({ $0.name.lowercased().contains(search) })
}
fileprivate func resetSearch()
{
switch self.mode
{
case .activities:
self.activities.removeAll()
self.activities.append(contentsOf: self.allActivities)
break
case .routes:
self.routes.removeAll()
self.routes.append(contentsOf: self.allRoutes)
break
case .segments:
self.segments.removeAll()
self.segments.append(contentsOf: self.allSegments)
break
default:
break
}
self.tableView.reloadData()
}
}
答案 0 :(得分:0)
我找到了解决方案,以便将来参考:
initSearchBar()中缺少以下行:
self.searchController.obscuresBackgroundDuringPresentation = false
我希望这会有所帮助。