点击"搜索"按钮

时间:2018-01-14 16:00:22

标签: uitableview uisearchbar ios11 uisearchcontroller

我非常喜欢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()
}

}

1 个答案:

答案 0 :(得分:0)

我找到了解决方案,以便将来参考:

initSearchBar()中缺少以下行:

self.searchController.obscuresBackgroundDuringPresentation = false

我希望这会有所帮助。