天道酬勤,学无止境

Peek and Pop on UITableView cells fails with UISearchController

Peek and Pop is working with a UISearchController. However, Peek and Pop stops working once you start searching the table using updateSearchResults.

I've extended Apple's Table Search with UISearchController demo to support Peek and Pop as an example:

Problem is when I start searching the table, Peek and Pop doesn't work anymore. It just select highlights it:

The updates I made were to MainTableViewController are:

class MainTableViewController: BaseTableViewController, UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating {
    override func viewDidLoad() {
        super.viewDidLoad()
        ...
        if traitCollection.forceTouchCapability == .available {
            registerForPreviewing(with: self, sourceView: tableView)
        }
    }
}

extension MainTableViewController: UIViewControllerPreviewingDelegate {

    func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
        guard let indexPath = tableView?.indexPathForRow(at: location),
            let cell = tableView?.cellForRow(at: indexPath),
            let controller = storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as? DetailViewController
                else { return nil }

        previewingContext.sourceRect = cell.frame

        controller.product = products[0]

        return controller
    }

    func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
        guard let controller = viewControllerToCommit as? DetailViewController else { return }
        controller.product = products[0]
        show(controller, sender: self)
    }
}

Is the search context controller interfering with peek and pop (could even be the keyboard)? I can get it to work when the table initially all data, but it does not once I start using the search. I attached a working sample here if you want to run it and see the issue.

评论

First, in your MainTableViewController.viewDidLoad() you need to also register your resultsTableController.tableView, since that is a separate view that will receive peek/pop information:

if traitCollection.forceTouchCapability == .available {
    previewingContext = registerForPreviewing(with: self, sourceView: tableView)
    if let resultVC = searchController.searchResultsController as? ResultsTableController {
        resultVC.registerForPreviewing(with: self, sourceView: resultVC.tableView)
    }
}

When testing this solution, I noticed a strange problem, that the first row in the result set wasn't peekable, and blank rows in the result set WERE peekable. So, the second fix in previewingContext(_:viewControllerForLocation:):

func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
    guard let tableView = previewingContext.sourceView as? UITableView,
        let indexPath = tableView.indexPathForRow(at: location),

In your original code, it was using the tableView property on the MainTableViewController instead of the tableView that was the sourceView for the interaction.

Now, this works when you're searching, and when you're not. However, when you've entered the search, but haven't entered any search text yet, the UISearchController is active, but the UITableView is the one from MainTableViewController, and you cannot register a view as a source view twice. So, we have a little more work to do:

// local property to store the result from registerForPreviewing(with:sourceView:)
var previewingContext: UIViewControllerPreviewing?

func didPresentSearchController(_ searchController: UISearchController) {
    if let context = previewingContext {
        unregisterForPreviewing(withContext: context)
        previewingContext = searchController.registerForPreviewing(with: self, sourceView: tableView)
    }
}

func didDismissSearchController(_ searchController: UISearchController) {
    if let context = previewingContext {
        searchController.unregisterForPreviewing(withContext: context)
        previewingContext = registerForPreviewing(with: self, sourceView: tableView)
    }
}

Basically, when the UISearchController is presented, we unregister MainTableViewController and register the search controller. When it is dismissed, we do the reverse.

With these changes, peek and pop work in all three states.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Tab Bar and UISearchController giving black screen
    I have two scenes which can be accessed through a tab bar, on scene 1 there is a search bar. the problem that I am facing is that while searching if I switch to the downloads tab - The navigation bar disappears. When I come back to the search tab, it gives me a black screen. This is screen 1 while searching - Now when I click on the downloads tab, the navigation bar disappears. Here is the view controller for the first screen - import UIKit import Alamofire import SwiftyJSON class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating
  • 使用UITableView实现UISearchController(Implement UISearchController with UITableView)
    问题 我只是想知道有关如何添加UISearchController以及如何将其与UITableViewController一起使用的Raywenderlich教程中的代码,我似乎无法正常运行,有人告诉我它可能已在iOS 8.0中弃用了,有人知道该怎么做吗? UISearchController内置在UIViewController不是StoryBoard中! 回答1 UISearchDisplayController已被弃用,取而代之UISearchController 。而且它是在IOS 8.0及更高版本。 UISearchController类定义一个接口,该接口与搜索结果控制器的内容一致地管理搜索栏的显示。 搜索结果控制器(由searchResultsController属性指定的UIViewController对象)管理搜索结果 https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UISearchController/index.html 这是一个示例,我该如何在UIViewController使用UITableView resding进行操作。如果要与UITableViewController一起使用,只需进行少量更改即可。 import UIKit class
  • 如何在UITableView中实现UISearchController-Swift(How to implement UISearchController in UITableView - Swift)
    问题 我是Swift的新手,我正在尝试向UIViewController类中的UITableView添加搜索功能。 我在Google上搜索了很多东西,发现UISearchDisplayController已被弃用并由UISearchController代替。 当我尝试搜索教程时,我没有找到专门针对UITableView任何教程。 其中一些是在UITableViewController实现的。 所以这是我的问题: 我们可以在UIViewController类中的UITableView中实现UISearchController吗? (我想我们可以) 如果可以的话,请转换用Objective-C编写的这些代码行。 或者,如果有一些非常好的教程,请告诉我。 @property (strong, nonatomic) UISearchController *searchController; UITableViewController *searchResultsController = [[UITableViewController alloc] init]; // Init UISearchController with the search results controller self.searchController = [[UISearchController alloc]
  • Cannot convert value of type '[Record]' to type 'Record' in coercion
    Im re-writing an iOS app I made using C# and Xamarin to Swift for obvious reasons of Xamarin's pricing, and low documentation. Following this tutorial for including a UISearchBar on my UITableView, i ran into this error: Cannot convert value of type '[Record]' to type 'Record' in coercion. Record.swift is a struct file I created to store the data that I will retrieve using cloudkit, but Im not sure how this error comes to be. Here is the problem part of MasterViewController.swift: func updateSearchResultsForSearchController(searchController: UISearchController) { self.filteredRecords.removeAll
  • iOS 8中不推荐使用searchDisplayController(searchDisplayController deprecated in iOS 8)
    问题 您如何纠正以下内容,以免出现任何警告? 我想念什么? 将searchResultsController更改为searchController时,出现错误“找不到对象” if (tableView == self.searchDisplayController.searchResultsTableView) { cell.textLabel.text = [searchResults objectAtIndex:indexPath.row]; } else { cell.textLabel.text = [_content objectAtIndex:indexPath.row]; } return cell; } -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { [self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController
  • UISearchController retain issue
    I am trying to use UISearchController however I confronted with retain issue that I can't solve. MainTableview has two sections. Section 1 Filtered Data based on some Regex Section 2 All Data I added UISearchController to my tableview and attached ResultsTableController as resultsTableController. It works when user search something, ResultsTableController comes forward and because I set tableview delegate to self, selecting item from ResultsTableController calls didSelectRowAtIndexPath in my MainTableViewController. However I have allocation issue if user selects something from
  • Swift UISearchController wired up in Core Data Project, app runs, but search not updating
    I have been wrestling the past few days with creating a filter in a Swift project for a TableViewController that uses Core Data. I finally figured out I need to use a UISearchController, create an NSPredicate for the searchController.searchBar, etc. I found this post EXTREMELY helpful, but after modeling my TVC after this project, I find "all the lights are on, but nobody's home". I can search, predicate is created in searchBar, add, remove, etc. but the cells don't update for the search. I'm missing something, but I don't know what. Here are the relevant portions of my code. class
  • How to prevent search bar from disappearing on scroll? iOS Swift
    I am creating a contact app. I have a scroll bar at the top of my table view. When I scroll down the search bar disapears. How to prevent search bar from disappearing on scroll? I want it to stay at the top of the page at all times like in the first picture. Here is a picture of my storyboard: Here is my view controller code for if the solution is not in storyboard: class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating { //manages search bar var searchController:UISearchController! var contacts = [Contact]() //array to hold contacts
  • Deleting from UISearchController's filtered search results
    I have a tableView sourcing its cell content from CoreData and have been replacing the SearchDisplayController (deprecated) with the new SearchController. I am using the same tableView controller to present both the full list of objects and also the filtered/searched objects. I have managed to get the search/filtering working fine and can move from the filtered list to detail views for those items, then edit and save changes back successfully to the filtered tableView. My problem is swiping to delete cells from the filtered list causes an run time error. Previously with the
  • UISearchController causes black screen Swift 2.0
    I have a strange problem in iOS 9 with Swift 2.0. I added UISearchController in my tableViewController but it causes a strange black screen problem. When I press the search bar and write something it shows my filtered results without any problem but when I tap another tab bar button like Bookmarks and after that when I tap tableViewController which is Most Viewed again it shows black screen like screen shot. There is my tableViewController; import UIKit class CitiesTableViewController: UITableViewController, UISearchResultsUpdating { // MARK: - Class Properties private var cities = [String]()
  • UISearchController updateSearchResults issue
    My question is I have implemented UISearchController in Swift 3 when I tried to filter it's easily filtered simple array but my case is little bit different I have one array which I fetch all the data from SQLite database in class so its array of class managerControlClassArray which has all the content of the class array. I want to filter the content in updateSearchResults delegate method but it's really difficult and stuck I did to much research and after not getting my desired query I found StackOverflow is very useful and question it if someone help's me, I would be grateful. Some Code
  • 从UISearchController的过滤搜索结果中删除(Deleting from UISearchController's filtered search results)
    问题 我有一个tableView从CoreData采购其单元格内容,并已用新的SearchController替换了SearchDisplayController (不建议使用)。 我正在使用同一个tableView控制器来显示对象的完整列表以及已过滤/搜索的对象。 我设法使搜索/过滤工作正常,并且可以从过滤列表移动到这些项目的详细视图,然后编辑并将更改成功保存回过滤的tableView中。 我的问题是要从已过滤列表中删除单元格,从而导致运行时错误。 以前使用SearchDisplayController可以轻松完成此操作,因为我可以访问SearchDisplayController's结果tableView,因此以下(伪)代码可以正常工作: func controllerDidChangeContent(controller: NSFetchedResultsController) { // If the search is active do this searchDisplayController!.searchResultsTableView.endUpdates() // else it isn't active so do this tableView.endUpdates() } } 不幸的是
  • failed to obtain a cell from its dataSource with swift 3
    I have the below UITableViewController attached as a searchResultsController: import UIKit import MapKit class LocationSearchTable : UITableViewController { var matchingItems:[MKMapItem] = [] var mapView: MKMapView? = nil override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self tableView.delegate = self } } extension LocationSearchTable : UISearchResultsUpdating { func updateSearchResults(for searchController: UISearchController){ guard let mapView = mapView, let searchBarText = searchController.searchBar.text else { return } let request = MKLocalSearchRequest() request
  • 从UITableViewCell进行3D触摸窥视和弹出如何将数据移交给其他UIViewController?(3D Touch Peek and Pop from UITableViewCell how to hand over data to other UIViewController?)
    问题 我的应用程序在Core Data对象中存储了不同的属性。 它们全部显示在UITableView中,如果单击单元格,则会显示DetailView。 像Master-Detail-XCode-Template中一样的常用东西。 现在,我想用peek和pop实现3D Touch。 像在“邮件”应用程序中一样,3D触摸一个单元格,获取预览,按得更深,然后弹出细节。 到目前为止,我已经完成了这项工作,但是我无法弄清楚如何在其中传递相应的数据 - (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location 和 - (void)previewingContext:(id <UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit 到另一个DetailViewController。 如果您只单击单元格(没有3D触摸),我将数据移交给 - (void)prepareForSegue
  • TableView with SearchController - DEINIT not called
    I have added a search bar and search display controller from the interface builder to my app. I am not able to get it to deinit (dealloc) properly. It is showing the following behavior (swift2, ios9): User doesn't search anything, just selects an item from tableView, DEINIT is called User searches something (or just taps in the search bar), cancel the search, select item from tableView, DEINIT is called User searches something (or just taps the search bar), and selects an item from tableView, DEINIT is NOT called :( The same behaviour occurs if I select "Back" in the navigation controller
  • 嵌入到NavigationItem中的破碎的UISearchBar动画(Broken UISearchBar animation embedded in NavigationItem)
    问题 我将搜索栏添加到导航项的新方法遇到问题。 如下图所示,有两个UIViewController,一个接一个,两个都有搜索栏。 问题是动画,当搜索栏在第一个视图控制器上可见而不在第二个视图控制器上可见时,动画很难看。 搜索栏占据的区域停留在屏幕上,然后突然消失。 该代码非常基础(项目中未进行其他任何更改): (我主要使用C#编写,因此此代码中可能存在错误。) ViewController.swift: import UIKit class ViewController: UITableViewController, UISearchResultsUpdating { override func loadView() { super.loadView() definesPresentationContext = true; navigationController?.navigationBar.prefersLargeTitles = true; navigationItem.largeTitleDisplayMode = .automatic; navigationItem.title = "VC" tableView.insetsContentViewsToSafeArea = true; tableView.dataSource = self; refreshControl
  • 3D Touch Peek and Pop from UITableViewCell how to hand over data to other UIViewController?
    my app stores different attributes in Core Data objects. They are all shown in a UITableView, if you click a cell, a DetailView is shown. the usual stuff like in the Master-Detail-XCode-Template. Now I want to implement 3D Touch with peek and pop. Like in the Mail app, 3D touch a cell, get preview, press deeper, pop in the detail. I got this working so far, but I can t figure out how to pass the corresponding data in - (nullable UIViewController *)previewingContext:(id <UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location and - (void)previewingContext:(id
  • 在Swift中智能搜索解析用户名无法正常工作(Smart-search for Parse Usernames in Swift not working)
    问题 我正在尝试在iOS应用中进行智能搜索,以便当用户在UISearchBar中键入字符时,结果会在搜索栏下方的表格视图中自动更新。 由于某些原因,当我在搜索栏中键入字符时,不会调用带有textDidChange的searchBar函数。 键入2个字符后调用。 因此,我的搜索结果总是比实际在搜索栏中输入的内容落后1步。 而且似乎search()函数每次被调用两次。 有任何想法吗? //FUNC: search func search(searchText: String? = nil){ if searchText == nil || searchText == "" { println("No users found.") } else { var query = PFUser.query() //MAKE CASE INSENSTIVE query!.whereKey("username", containsString: searchText!) query!.findObjectsInBackgroundWithBlock { (results, error) -> Void in if error != nil { println(error) } else { if let res = results { self.data = res as? [PFUser] } }
  • Display table view when searchBar (from searchController) begin edited Swift
    I already seen this question : How to show tableview when user taps searchbar swift It's the same issue as me but when I use the answer it can't work for me. When I click on the button search, only the searchbar appears on the search controller then if I type something the tableView doesn't appear at all. I use Swift 3. The best example for what I want to do is the Instagram search function. When user tap the searchbar a tableView comes as a subView. I show you my current code of my SearchViewController (where I search for a username in Firebase) : class SearchViewController: UIViewController
  • Google自动完成教程将api迅速化(Tutorial for Google autocomplete places api for swift)
    问题 我想拥有一个自动填充文本字段,该文本字段可以像我的android那样自动填充位置: https://developers.google.com/places/training/autocomplete-android 有谁知道我在哪里可以找到本教程或示例的教程? 谢谢! 回答1 脚步 : 在您的快速项目中添加Alamofire CocoaPods。 在Google API控制台上找到您的Google Place API密钥。 添加以下代码 ViewController.swift import UIKit class ViewController: UIViewController { override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let gpaViewController = GooglePlacesAutocomplete( apiKey: "YOUR GOOGLE PLACE API KEY", placeType: .Address ) gpaViewController.placeDelegate = self presentViewController(gpaViewController, animated: true, completion: nil) }