单击“搜索”按钮时的奇怪行为

Posted

技术标签:

【中文标题】单击“搜索”按钮时的奇怪行为【英文标题】:Odd behavior when clicking "Search" button 【发布时间】:2018-01-14 16:00:21 【问题描述】:

我真的很喜欢 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】:

我找到了解决方案,供以后参考:

initSearchBar() 中缺少以下行:

self.searchController.obscuresBackgroundDuringPresentation = false

我希望这会有所帮助。

【讨论】:

以上是关于单击“搜索”按钮时的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

将 UIButton 添加到 UICollectionViewCell 时的奇怪行为

将 Scaffold 放入 NestedScrollview 时的奇怪行为?在 SliverAppbar 下剪辑时自动滚动到顶部

如何覆盖搜索视图中的向上按钮行为

Android ListView 突出显示会导致奇怪的行为

react-redux 中的奇怪按钮行为

CLLocationManager 奇怪的行为