UITableView can't scroll - ios

My UITableView can't scroll, I tried everything I could have possibly done.
Getting a little desperate here.
the tableview implementation here is actually pretty simple, but can't make it work...
Will post the code below:
class RepresentableViewController: DynamicBackgroundViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
// MARK: - Properties
var representables: Array<TableCellRepresentable>? {
didSet{
if !self.isAnimatingTable {
self.tableView.reloadData()
}
if self.representables != nil {
self.stopAnimatingIndicator()
}
else {
self.startAnimatingIndicator()
}
}
}
var cellReuseId: String {
return RepresentableTableViewCell.reuseId
}
var isAnimatingTable: Bool = false
private(set) var isSearching: Bool = false
private(set) var searchResults: Array<TableCellRepresentable>? {
didSet {
self.tableView.reloadData()
}
}
var searchResultsCount: Int {
return self.searchResults != nil ? self.searchResults!.count : 0
}
var activeRepresentables: Array<TableCellRepresentable>? {
return self.isSearching ? self.searchResults : self.representables
}
var activeRepresentablesCount: Int {
return self.activeRepresentables != nil ? self.activeRepresentables!.count : 0
}
private(set) var lastSelectedIndex: NSIndexPath?
// MARK: Outlets
#IBOutlet weak var tableView: UITableView!
weak var activityIndicator: UIActivityIndicatorView?
#IBOutlet weak var searchBar: UISearchBar!
// MARK: - Methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.setupCell()
self.startAnimatingIndicator()
}
private func setupCell() {
let nib = UINib(nibName: "RepresentableTableViewCell", bundle: nil)
self.tableView.registerNib(nib, forCellReuseIdentifier: RepresentableTableViewCell.reuseId)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if self.representables == nil {
self.postRequestRepresentablesNotification()
}
}
private func postRequestRepresentablesNotification() {
NSNotificationCenter.defaultCenter().postNotificationName(RepresentableViewController.requestRepresentablesNotificationName, object: self, userInfo: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
self.clearRepresentablesIfNotVisible()
}
func insertToTable(item: TableCellRepresentable) {
self.isAnimatingTable = true
if self.representables == nil {
self.self.representables = []
}
self.representables!.append(item)
self.tableView.reloadData()
self.isAnimatingTable = false
}
func removeFromTable(atIndexPath index: NSIndexPath) {
self.isAnimatingTable = true
self.representables!.removeAtIndex(index.row)
self.tableView.deleteRowsAtIndexPaths([index], withRowAnimation: .Automatic)
self.isAnimatingTable = false
}
private func clearRepresentablesIfNotVisible() {
if !self.isViewLoaded() && !(self.view.window != nil) {
self.representables = nil
}
}
private func startAnimatingIndicator() {
if self.activityIndicator == nil {
let indicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
indicator.hidesWhenStopped = true
indicator.color = RGBColor(r: 35, g: 131, b: 250, alpha: 1.0)
indicator.center = self.view.center
self.activityIndicator = indicator
self.view.addSubview(indicator)
self.shouldBringToFront?.append(indicator)
indicator.startAnimating()
}
}
private func stopAnimatingIndicator() {
if let indicator = self.activityIndicator {
if let shouldBring = self.shouldBringToFront, index = find(shouldBring, indicator) {
self.shouldBringToFront!.removeAtIndex(index)
}
indicator.stopAnimating()
indicator.removeFromSuperview()
self.activityIndicator = nil
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}*/
// MARK: - Protocols
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.activeRepresentables != nil ? self.activeRepresentables!.count : 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(self.cellReuseId, forIndexPath: indexPath) as! RepresentableTableViewCell
cell.object = self.activeRepresentables![indexPath.row]
return cell
}
// MARK: UITableViewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.lastSelectedIndex = indexPath
NSNotificationCenter.defaultCenter().postNotificationName(RepresentableViewController.didSelectARepresentableNotificationName, object: self, userInfo: [RepresentableViewController.representableKey: self.activeRepresentables![indexPath.row]])
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0
}
// MARK: SearchBarDelegate
private func filterProducts(searchText: String) {
if searchText != "" {
self.searchResults = self.representables?.filter({ (cur: TableCellRepresentable) -> Bool in
let lowerCase: String = searchText.lowercaseString
let titleMatch: Bool = cur.title.lowercaseString.rangeOfString(lowerCase) != nil
let subtitleMatch: Bool = cur.subtitle.lowercaseString.rangeOfString(lowerCase) != nil
let detailMatch: Bool = cur.detail?.lowercaseString.rangeOfString(lowerCase) != nil
return titleMatch || subtitleMatch || detailMatch
})
}
else {
self.searchResults = self.representables
}
}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
self.filterProducts(searchText)
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
self.isSearching = false
self.searchBar.text = ""
self.searchResults = nil
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
self.isSearching = true
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchBar.endEditing(true)
}
// MARK: - Static Properties and Methods
class var didSelectARepresentableNotificationName: String {
return "RepresentableViewController-didSelectARepresentableNotification"
}
class var requestRepresentablesNotificationName: String {
return "RepresentableViewController-RequestRepresentablesNotification"
}
class var representableKey: String {
return "Representable"
}
}
can't figure it out, can someone help me?
thanks.
EDITED
This issue is being caused by a PanGesture at the UITableViewCells, how can I solve this? I still need this pan gesture to move content at the cell.

Fixed with this piece of code at the UITableViewCell
override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer
{
let translation = panGestureRecognizer.translationInView(superview!)
if fabs(translation.x) > fabs(translation.y)
{
return true
}
return false
}
return false
}

Related

The search bar does not search for words entered in the search field

I have a problem with the search bar, when I load the app the Json data is loaded correctly in the table view, but if I enter a word in the search field nothing happens, the data is not searched and the tableView remains the same.
ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var popularMoviesArray = [Results]()
var swiftManager = SwiftManager()
var tableViewCell = TableViewCell()
#IBOutlet weak var tableView: UITableView!
// START SEARCHBAR
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var labelError: UILabel!
var filteredMoviesArray = [Results]() {
didSet {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
// END SEARCHBAR
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
swiftManager.delegate = self
// START SEARCHBAR
searchBar.delegate = self
searchBar.placeholder = "Search here..."
// END SEARCHBAR
swiftManager.fetchUrl()
}
// START SEARCHBAR
func rowOk() {
labelError.backgroundColor = UIColor.white
labelError.text = ""
}
func rowError() {
labelError.textColor = UIColor.white
labelError.backgroundColor = UIColor.red
labelError.textAlignment = .center
labelError.text = "no records found"
}
// END SEARCHBAR
// MARK: - TableView Datasource Methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// START SEARCHBAR
if filteredMoviesArray.count != 0 {
rowOk()
print("OK - \(filteredMoviesArray.count)")
return filteredMoviesArray.count
} else {
rowError()
print("ERROR - \(filteredMoviesArray.count)")
return filteredMoviesArray.count
}
// END SEARCHBAR
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let item = filteredMoviesArray[indexPath.row]
cell.labelTitle.text = item.title
cell.labelYear.text = labelYearFormatter
cell.labelRate.text = String(item.vote_average ?? 0.0)
cell.labelOreview.text = item.overview
return cell
}
// MARK: - TableView Delegate Methods
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToDetail", sender: indexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier != nil else {
return
}
let letRow = sender as? Int
switch segue.identifier {
case "goToDetail":
(segue.destination as! ViewControllerDetail).itemDetail = filteredMoviesArray[letRow!]
default:
return
}
}
}
extension SwiftManagerDelegate
//MARK: - SwiftManagerDelegate
extension ViewController: SwiftManagerDelegate {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.filteredMoviesArray = swiftData.results
self.tableView.reloadData()
}
}
func didFailWithError(error: Error) {
print(error)
}
}
extension UISearchBarDelegate
//MARK: - UISearchBarDelegate
// START SEARCHBAR
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
guard
let searchText = searchBar.text
else {
return
}
if searchText.isEmpty == true {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.filteredMoviesArray = swiftData.results
self.tableView.reloadData()
}
}
print("EMPTY")
return
} else {
func didUpdateStruct(_ swiftManager: SwiftManager, swiftData: SwiftData) {
DispatchQueue.main.async {
self.filteredMoviesArray = swiftData.results.filter {
$0.title!.uppercased().contains(searchText.uppercased())
}
self.tableView.reloadData()
}
}
print("FULL")
return
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
swiftManager.fetchUrl()
}
}
// END SEARCHBAR

SearchController issue, when search the displayController shows a spacing from the Searchbar

The issue is this:
In the storyboard, I must uncheck the Adjust Scroll View Insets, because if not do this, I will get a other issue(https://stackoverflow.com/questions/40974647/uisearchcontroller-issue-nslayoutattribute-do-not-work-in-real-device), and I don't know this if is affect the issue here.(I test in simulator, if check Adjust Scroll View Insets, the issue here will not appear )
My code
import UIKit
import SVProgressHUD
class ChooseStoreViewController: UIViewController,UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
var ori_dataSource: [StoreListModel] = [StoreListModel]()
var dataSource = [String]()
var filterdDataSource = [String]()
var resultSearchController = UISearchController()
var choosedStore:StoreListModel? = nil
var userInfoFromChooseTerant:[String:Any]?
#IBOutlet weak var top_constraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
initData()
initUI()
}
// MARK: - view life
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.isNavigationBarHidden = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.isNavigationBarHidden = true
}
func initData() {
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.resultSearchController.searchBar.placeholder = "search"
self.resultSearchController.searchBar.tintColor = UIColor.black
self.resultSearchController.searchBar.delegate = self
self.tableView.tableHeaderView = self.resultSearchController.searchBar
let nib = UINib(nibName: "TerantListCell", bundle: nil)
// Required if our subclasses are to use: dequeueReusableCellWithIdentifier:forIndexPath:
//tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.tableFooterView = UIView.init()
self.tableView.reloadData()
networkForStoreList()
}
func initUI() {
let backNavItem:UIBarButtonItem = UtilSwift.addBackButtonItem(nil, controlelr: self)
backNavItem.action = #selector(navBack)
// print(userInfoFromChooseTerant!)
tableView.separatorStyle = UITableViewCellSeparatorStyle.none
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
let chooseRole: ChooseRoleViewController = segue.destination as! ChooseRoleViewController
chooseRole.userInfoFromChooseStore = self.userInfoFromChooseTerant
}
// MARK: - search delegate
func searchBarCancelButtonClicked() {
for item:NSLayoutConstraint in self.tableView.constraints {
self.view.setNeedsLayout()
if item.firstAttribute == NSLayoutAttribute.top {
item.constant = 0
}
}
}
// MARK: - searchbar delegate
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setValue("cancel", forKey:"_cancelButtonText")
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
}
// MARK: - private methods
func navBack() {
_ = self.navigationController?.popViewController(animated: true)
}
// MARK: - actions
#IBAction func unwindToChooseStoreVCFromChooseRole(segue: UIStoryboardSegue){
}
#IBAction func nextStepAction(_ sender: UIButton) {
/*if choosedStore == nil {
let lml_alert: LMLDropdownAlertView = LMLDropdownAlertView.init(frame: self.view.bounds)
lml_alert.showAlert(title: Global.hint, detail_Title: "select", cancleButtonTitle: "cacnel", confirmButtonTitle: "confirm", action: { (button) in
})
return
}*/
self.resultSearchController.isActive = false
if self.choosedStore != nil {
_ = self.userInfoFromChooseTerant?.updateValue(self.choosedStore!.userId, forKey: "store_id")
}
self.performSegue(withIdentifier: "ChooseStoreVCToChooseRoleVC", sender: self)
}
// MARK: - network
func networkForStoreList() {
let params:[String:String] = [
"createTime":"-1",
"userId" : self.userInfoFromChooseTerant!["affiliated_id"] as! String
]
// url_terantList
Mysevers.afpost(withHud: true, andAddressname: Global.url_listStore, parmas: params, requestSuccess: { (result) in
let stateCode = UtilSwift.getNetStateCode(result: result as Any, key: Global.net_key_stateCode)
if stateCode == 0 {
let storeArr:[[String : Any]] = UtilSwift.getNetAnyObject(result: result as Any, key: "list") as! [[String : Any]] // Global.net_key_bussines
//self.ori_dataSource = terantArr
for item:[String: Any] in storeArr {
let store_list_model: StoreListModel = StoreListModel.initStoreListModelWithDic(dic: item)
self.ori_dataSource.append(store_list_model)
}
for item:StoreListModel in self.ori_dataSource {
self.dataSource.append(item.name)
}
self.tableView.reloadData()
}else if stateCode == -1 {
SVProgressHUD.showError(withStatus: "err")
}
}, failBlcok: {
SVProgressHUD.showError(withStatus: "err")
})
}
// MARK: - tableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.resultSearchController.isActive {
return filterdDataSource.count
}else {
return dataSource.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TerantListCell = tableView.dequeueReusableCell(withIdentifier: "TerantListCell", for: indexPath) as! TerantListCell
if self.resultSearchController.isActive {
cell.title_label.text = self.filterdDataSource[indexPath.row]
}else {
cell.title_label?.text = self.dataSource[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.choosedStore = self.ori_dataSource[indexPath.row]
}
// MARK: - regexp
func updateSearchResults(for searchController: UISearchController) {
self.filterdDataSource.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (self.dataSource as NSArray).filtered(using: searchPredicate)
self.filterdDataSource = array as! [String]
self.tableView.reloadData()
}
}
Go to ".storyboard" file where "ChooseStoreViewController" exist. Then click on UITableView and change tableView constraints as follows:
Check Top Space constraint.

Strange issue, space of my UISearchController

The issue is like this:
There has space between searchbar and navbar:
And in the Debug in Hierarchy:
The table View
The wrapper View, we can see the space (20 pix)
And in the storyboard, I set the constraint to the tableView, attention: the navigationBar is draged by myself, the native is hide by me.
My Code
import UIKit
import SVProgressHUD
class StoreListViewController: UIViewController, UISearchBarDelegate, UITableViewDelegate,UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var navbar: UINavigationBar!
#IBOutlet weak var tableView: UITableView!
var ori_dataSource: [StoreListModel] = [StoreListModel]()
var dataSource = [String]()
var filterdDataSource = [String]()
var resultSearchController = UISearchController()
var choosedStore:StoreListModel? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
initData()
initUI()
}
// MARK: - init
func initData() {
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.resultSearchController.searchBar.placeholder = "search"
self.resultSearchController.searchBar.tintColor = UIColor.black
self.resultSearchController.searchBar.delegate = self
self.tableView.tableHeaderView = self.resultSearchController.searchBar
let nib = UINib(nibName: "TerantListCell", bundle: nil)
// Required if our subclasses are to use: dequeueReusableCellWithIdentifier:forIndexPath:
//tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.register(nib, forCellReuseIdentifier: "TerantListCell")
self.tableView.tableFooterView = UIView.init()
self.tableView.reloadData()
networkForStoreList()
}
func initUI() {
tableView.separatorStyle = UITableViewCellSeparatorStyle.none
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "StoreListGotoStoreDetailVC" {
let detail_vc:StoreDetailVC = segue.destination as! StoreDetailVC
detail_vc.store_info = self.choosedStore
}
}
// MARK: - delegate
func searchBarCancelButtonClicked() {
for item:NSLayoutConstraint in self.tableView.constraints {
if item.firstAttribute == NSLayoutAttribute.top {
item.constant = 0
}
}
}
// MARK: - searchbar delegate
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setValue("cancel", forKey:"_cancelButtonText")
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 0
}
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 64
}
}
}
// MARK: - private methods
// MARK: - actions
// MARK: - unwind
#IBAction func unwindToStoreListVCFromStoreDetailVC(segue: UIStoryboardSegue) {
}
// MARK: - network
func networkForStoreList() {
let userStatic: UserStaticSwift = UserStaticSwift.sharedInstance()
let params:[String:String] = [
"createTime":"-1",
"userId" : userStatic.userId
]
// url_listUsers
Mysevers.afpost(withHud: true, andAddressname: Global.url_listStore, parmas: params, requestSuccess: { (result) in
let stateCode = UtilSwift.getNetStateCode(result: result as Any, key: Global.net_key_stateCode)
if stateCode == 0 {
let userArr:[[String : Any]] = UtilSwift.getNetAnyObject(result: result as Any, key: "list") as! [[String : Any]] // Global.net_key_bussiness
//self.ori_dataSource = terantArr
for item:[String: Any] in userArr {
let store_list_model: StoreListModel = StoreListModel.initStoreListModelWithDic(dic: item)
self.ori_dataSource.append(store_list_model)
}
for item:StoreListModel in self.ori_dataSource {
self.dataSource.append(item.name)
}
self.tableView.reloadData()
}else if stateCode == -1 {
SVProgressHUD.showError(withStatus: "err")
}
}, failBlcok: {
SVProgressHUD.showError(withStatus: "fail")
})
}
// MARK: - tableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.resultSearchController.isActive {
return filterdDataSource.count
}else {
return dataSource.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TerantListCell = tableView.dequeueReusableCell(withIdentifier: "TerantListCell", for: indexPath) as! TerantListCell
if self.resultSearchController.isActive {
cell.title_label.text = self.filterdDataSource[indexPath.row]
}else {
cell.title_label?.text = self.dataSource[indexPath.row]
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.choosedStore = self.ori_dataSource[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
self.performSegue(withIdentifier: "StoreListGotoStoreDetailVC", sender: self)
}
// MARK: -
func updateSearchResults(for searchController: UISearchController) {
self.filterdDataSource.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (self.dataSource as NSArray).filtered(using: searchPredicate)
self.filterdDataSource = array as! [String]
self.tableView.reloadData()
}
}
ATTEMPT - 1
When I uncheck the Adjust Scroll View Insets, first come into the vc, the issue is nonexistent, but if I click the searchBar, the issue will come again, I suspect my code if is somewhere mistake:
ATTEMPT - 2
If I try this code below:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 44 // before is 64.
}
}
}
Since I don't know how you constraints your views. I guess the problem is due to automaticallyAdjustsScrollViewInsets. You should automaticallyAdjustsScrollViewInsets = false of your ViewController. Or you should constraints your UITableView to View.Top instead of TopLayoutGuide.Bottom.
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 44 // changes this one line and check it if any problem then put comment below.
}
}
}
After many attempt:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for item:NSLayoutConstraint in self.navbar.constraints {
if item.firstAttribute == NSLayoutAttribute.height {
item.constant = 64
}
}
// set this help me! :)
tableView.contentInset = UIEdgeInsets.zero
tableView.scrollIndicatorInsets = UIEdgeInsets.zero
}

selecting cell in tableview while UISearchController is active, doesnt present next view?

I have made a tableview where you can select a cell, and then the viewcontroller will perform a segue to the next view, which works perfectly fine when you are not using the searchcontroller.
Then when you are using the searchcontroller, it filters the tableview as it should, and the segue is called in didSelectRowAtIndexPath, and the prepareForSegue is called. The problem then is that the view it should segue to is not presented? I can see that the code in the class connected to the view is running, so the segue is performed, it is just the view that does not follow. What am i missing
class CompanyListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
let objectMapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()
var activityIndicatorView: SWActivityIndicatorView!
var resultSearchController: UISearchController!
var allCompanies: [Company] = []
var filteredCompanies = [Company]()
override func viewDidLoad() {
super.viewDidLoad()
// set delegates
tableView.delegate = self
tableView.dataSource = self
configureSearchController()
// initialize activity indicator view
self.activityIndicatorView = SWActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
activityIndicatorView.hidesWhenStopped = true
activityIndicatorView.color = UIColor.lightGrayColor()
self.view.addSubview(activityIndicatorView)
self.activityIndicatorView.center = self.view.center
activityIndicatorView.startAnimating()
// fetch all records from backend
fetchAllRecords({(errors: [NSError]?) -> Void in if errors != nil {print(errors)}})
}
func configureSearchController() {
// Initialize and perform a minimum configuration to the search controller.
// Search Bar
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController?.searchBar.autocapitalizationType = .None
self.tableView.tableHeaderView = self.resultSearchController?.searchBar
resultSearchController?.dimsBackgroundDuringPresentation = false
self.resultSearchController?.searchResultsUpdater = self
definesPresentationContext = true
}
// search delegate method
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.filterContentForSearchText(searchController.searchBar.text!)
}
// Filter method, which filters by companyName, and reloads tableview
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredCompanies = allCompanies.filter { company in
return company._companyName!.lowercaseString.containsString(searchText.lowercaseString)
}
tableView.reloadData()
}
// fetch all records from backend
func fetchAllRecords(completionHandler: (errors: [NSError]?) -> Void) {
let scanExpression = AWSDynamoDBScanExpression()
objectMapper.scan(Company.self, expression: scanExpression) { (response: AWSDynamoDBPaginatedOutput?, error: NSError?) in
dispatch_async(dispatch_get_main_queue(), {
// if error
if let error = error {
completionHandler(errors: [error]);
}
//if success
else {
self.allCompanies = response!.items as! [Company]
self.tableView.reloadData()
self.activityIndicatorView.stopAnimating()
}
})
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if resultSearchController.active && resultSearchController.searchBar.text != "" {
return filteredCompanies.count
}
return allCompanies.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell:CompanyListTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("companyCell") as! CompanyListTableViewCell
// set the text from the data model
let company:Company?
if resultSearchController.active && resultSearchController.searchBar.text != "" {
company = self.filteredCompanies[indexPath.row]
} else {
company = self.allCompanies[indexPath.row]
}
cell.titleLabel.text = company!._companyName
cell.imageview?.image = UIImage(named: "placeholder")
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("segueToProfile", sender: self)
}
// send selected company with segue to profile
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "segueToProfile"){
let indexPath = tableView.indexPathForSelectedRow
//tableView.deselectRowAtIndexPath(indexPath!, animated: true)
let selectedRow = indexPath!.row
let profileVC = segue.destinationViewController as! ProfileViewController
if resultSearchController.active{
print(filteredCompanies[selectedRow])
profileVC.company = filteredCompanies[selectedRow]
} else {
profileVC.company = allCompanies[selectedRow]
}
}
}
}
The console is saying this, but i dont know if that has anything to do with this?
2016-11-26 15:54:07.300 Lostandfound[949:2474251] Warning: Attempt to present on which is already presenting
Here is the example of TableView with SearchBar control.You should remove didSelectRowAtIndexPath method and use prepareForSegue method for Determine the selected row in TableView.Like this...
Example:
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate
{
#IBOutlet weak var SerchBar: UISearchBar!
#IBOutlet weak var TableView: UITableView!
var searchActive : Bool = false
var data = ["San Francisco","New York","San Jose","Chicago","Los Angeles","Austin","Seattle"]
var filtered:[String] = []
override func viewDidLoad()
{
super.viewDidLoad()
}
private func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if(searchActive)
{
return filtered.count
}
return data.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.TableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
if(searchActive)
{
cell.Label.text = filtered[indexPath.row]
}
else
{
cell.Label.text = data[indexPath.row]
}
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any!)
{
if let cell = sender as? TableViewCell
{
let i = TableView.indexPath(for: cell)!.row
if segue.identifier == "segue1"
{
if(searchActive)
{
let name1 = segue.destination as! SecondView
name1.str = self.filtered[i]
}
else
{
let name1 = segue.destination as! SecondView
name1.str = self.data[i]
}
}
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
filtered = data.filter({ (text) -> Bool in
let tmp: NSString = text as NSString
let range = tmp.range(of: searchText, options: .caseInsensitive)
return range.location != NSNotFound
})
if(filtered.count == 0)
{
searchActive = false;
}
else
{
searchActive = true;
}
self.TableView.reloadData()
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar)
{
searchActive = true;
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar)
{
searchActive = false;
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
{
searchActive = false;
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar)
{
searchActive = false;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
Your SecondView class is:
import UIKit
class SecondView: UIViewController
{
#IBOutlet weak var label: UILabel!
var str:String!
override func viewDidLoad()
{
super.viewDidLoad()
self.label.text = str
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
}
And your TableViewCell is:
import UIKit
class TableViewCell: UITableViewCell
{
#IBOutlet weak var Label: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
}

Mapping between TableView and SearchView

I have a searchController added programatically to my UIViewController on top of my table view. My ViewController handles segues based on rowIndex which poses a problem with my searchview which alters the indices. I have added a mapping array to fix that, but its not working as intended, with out of bounds errors sometimes and it not matching to correct elements. My code below.
import UIKit
class WebpageController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UISearchResultsUpdating {
var names: [String] = [String]()
var counter = 0
var counter2 = 0
var school: String = String()
var index: Int = Int()
var searchResults: [String] = [String]()
var searchController = UISearchController(searchResultsController: nil)
var searchIndex: [Int] = [Int]()
#IBOutlet var tables: UITableView!
var refreshControl: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.sizeToFit()
definesPresentationContext = true
tables.tableHeaderView = searchController.searchBar
names = HtmlController.loadData() as NSArray as! [String]
names.removeAtIndex(0)
clean()
refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(WebpageController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
tables.addSubview(refreshControl)
// Do any additional setup after loading the view.
}
func refresh(sender: AnyObject)
{
names = HtmlController.loadData() as NSArray as! [String]
names.removeAtIndex(0)
clean()
tables.reloadData()
refreshControl.endRefreshing()
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchText = searchController.searchBar.text
filterContentForSearchText(searchText!)
tables.reloadData()
}
func filterContentForSearchText(searchText: String)
{
if(searchText == "")
{
searchResults = names
}
else{
searchResults = names.filter({ ( a: String) -> Bool in
let nameMatch = a.rangeOfString(searchText, options:
NSStringCompareOptions.CaseInsensitiveSearch)
return nameMatch != nil
})
while counter2 < searchResults.count
{
while counter < names.count{
if names[counter] == searchResults[counter2]
{
if searchIndex.count > counter2 && counter > 0
{
searchIndex.removeAtIndex(counter2)
}
searchIndex.insert(counter, atIndex: counter2)
}
counter += 1
}
counter2 += 1
}
}
}
#IBOutlet weak var Table: UITableView!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func clean()
{
var length = names.count
var i = 0;
var bool = false
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("School") == nil
{
school = "11Staff"
defaults.setObject("11", forKey: "School")
}
else{
school = (defaults.objectForKey("School") as! String) + "Staff"
}
var extra: [String] = [String]()
let bundleidentifier = NSBundle.mainBundle().bundleIdentifier
if let aStreamReader = StreamReader(path: NSBundle.mainBundle().pathForResource(school, ofType: "txt")!)
{
defer {
aStreamReader.close()
}
while let line = aStreamReader.nextLine() {
extra.append(line)
}
}
for String in extra
{
while i < length && bool == false
{
if((String.rangeOfString(names[i].uppercaseString)) != nil)
{
names.removeAtIndex(i)
i -= 1
bool = true
length = names.count
}
i+=1;
}
bool = false
i = 0;
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if searchController.active
{
return searchResults.count
}
else{
return names.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell
if let reusedCell = tableView.dequeueReusableCellWithIdentifier("Cell") {
cell = reusedCell
} else {
cell = UITableViewCell(style: .Default, reuseIdentifier: "Cell")
}
if !searchController.active{
if let label = cell.textLabel {
label.text = names[indexPath.row].uppercaseString
}
}
else{
cell.textLabel!.text = searchResults[indexPath.row].uppercaseString
}
return cell }
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
index = indexPath.row
performSegueWithIdentifier("WebTransfer", sender:self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Destination: WebsiteController = segue.destinationViewController as! WebsiteController
if !searchController.active
{
Destination.index = index
}
else{
Destination.index = searchIndex[index]
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

Resources