When I'm in the middle of a search and then switch UItabs, ViewWillDisappear does not get called. Any idea as to why ViewWillDisappear does not get called when I have filtered results displaying and switch tabs?
func updateSearchResultsForSearchController(searchController: UISearchController) {
if self.searchController?.searchBar.text.lengthOfBytesUsingEncoding(NSUTF32StringEncoding) > 0 {
if let results = self.results {
results.removeAllObjects()
} else {
results = NSMutableArray(capacity: MyVariables.dictionary.keys.array.count)
}
let searchBarText = self.searchController!.searchBar.text
let predicate = NSPredicate(block: { (city: AnyObject!, b: [NSObject : AnyObject]!) -> Bool in
var range: NSRange = NSMakeRange(0, 0)
if city is NSString {
range = city.rangeOfString(searchBarText, options: NSStringCompareOptions.CaseInsensitiveSearch)
}
return range.location != NSNotFound
})
// Get results from predicate and add them to the appropriate array.
let filteredArray = (MyVariables.dictionary.keys.array as NSArray).filteredArrayUsingPredicate(predicate)
self.results?.addObjectsFromArray(filteredArray)
// Reload a table with results.
self.searchResultsController?.tableView.reloadData()
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(self.identifier) as! UITableViewCell
var text: String?
var imgtext:AnyObject?
if tableView == self.searchResultsController?.tableView {
if let results = self.results {
text = self.results!.objectAtIndex(indexPath.row) as? String
imgtext = MyVariables.dictionary[text!]
let decodedData = NSData(base64EncodedString: imgtext! as! String, options: NSDataBase64DecodingOptions(rawValue: 0) )
var decodedimage = UIImage(data: decodedData!)
cell.imageView?.image = decodedimage
}
} else {
text = MyVariables.dictionary.keys.array[indexPath.row] as String
}
cell.textLabel!.text = text
return cell
}
On the Load
override func viewDidLoad() {
super.viewDidLoad()
let resultsTableView = UITableView(frame: self.tableView.frame)
self.searchResultsController = UITableViewController()
self.searchResultsController?.tableView = resultsTableView
self.searchResultsController?.tableView.dataSource = self
self.searchResultsController?.tableView.delegate = self
// Register cell class for the identifier.
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: self.identifier)
self.searchResultsController?.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: self.identifier)
self.searchController = UISearchController(searchResultsController: self.searchResultsController!)
self.searchController?.searchResultsUpdater = self
self.searchController?.delegate = self
self.searchController?.searchBar.sizeToFit()
self.searchController?.hidesNavigationBarDuringPresentation = false;
self.tableView.tableHeaderView = self.searchController?.searchBar
self.definesPresentationContext = true
}
Had the same issue. viewWillDisappear is not called on the UITableViewController, but it is called in the UISearchController.
So I subclassed UISearchController and overrode the viewWillDisappear method. In my case I just needed to deactivate the search controller.
class SearchController: UISearchController {
override func viewWillDisappear(_ animated: Bool) {
// to avoid black screen when switching tabs while searching
isActive = false
}
}
Similar to #user5130344 I found that subclassing resolved my issue, although I found that isActive = false cleared the search bar where I wanted the search query to remain on returning to the view.
Here's my subclass instead - this fixed my issue with iOS 13 dismissing the parent view:
class MySearchController: UISearchController {
override func viewWillDisappear(_ animated: Bool) {
// to avoid black screen when switching tabs while searching
self.dismiss(animated: true)
}
}
I think its the problem with the xcode . Try to close it and reopen the project once again and try to run again
Related
The error:
[Assert] Surprise! Activating a search controller whose navigation item is not at the top of the stack. This case needs examination in UIKit. items = (null),
search hosting item = <UINavigationItem: 0x1068473a0> title='PARTS' style=navigator leftBarButtonItems=0x282bfb8d0 rightBarButtonItems=0x282bfb890 searchController=0x110024400 hidesSearchBarWhenScrolling
Why am I getting this error and how do I fix it? This question is similar to another post, but there was only one response to it and the response was not detailed at all (therefore not helpful).
import UIKit
import SPStorkController
struct Part {
var title: String?
var location: String?
var selected: Bool? = false
}
class InspectorViewController: UIViewController, UINavigationControllerDelegate, UITableViewDataSource, UITableViewDelegate, UISearchResultsUpdating, UISearchBarDelegate {
private let initials = InspectorPartsList.getInitials() // model
private var parts = InspectorPartsList.getDamageUnrelatedParts() // model
var filteredParts: [Part] = [] // model
var searching = false
var searchController = UISearchController(searchResultsController: nil)
lazy var searchBar: UISearchBar = UISearchBar()
var isSearchBarEmpty: Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
var navBar = UINavigationBar()
let inspectorTableView = UITableView() // tableView
var darkTheme = Bool()
override func viewDidLoad() {
super.viewDidLoad()
// setup the navigation bar
setupNavBar()
// add the table view
setupInspectorTableView()
// add the search controller to the navigation bar
setupSearchController()
}
func setupNavBar() {
navBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 100))
view.addSubview(navBar)
let navItem = UINavigationItem(title: "PARTS")
let doneItem = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: #selector(self.addBtnTapped))
let cancelItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: nil, action: #selector(self.cancelBtnTapped))
navItem.rightBarButtonItem = doneItem
navItem.leftBarButtonItem = cancelItem
navItem.searchController = searchController
navBar.setItems([navItem], animated: false)
}
#objc func cancelBtnTapped() {
// dismiss the storkView
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
}
#objc func addBtnTapped() {
// get all of the selected rows
// Update the InspectionData model with the selected items... this will allow us to update the InspectionTableView in the other view
// create an empty array for the selected parts
var selectedParts = [Part]()
// loop through every selected index and append it to the selectedParts array
for part in parts {
if part.selected! {
selectedParts.append(part)
}
}
// update the InspectionData model
if !selectedParts.isEmpty { // not empty
InspectionData.sharedInstance.partsData?.append(contentsOf: selectedParts)
// update the inspectionTableView
updateInspectionTableView()
}
// dismiss the storkView
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
}
func cancelAddPart() {
// dismiss the storkView
SPStorkController.dismissWithConfirmation(controller: self, completion: nil)
}
private func setupInspectorTableView() {
// set the data source
inspectorTableView.dataSource = self
// set the delegate
inspectorTableView.delegate = self
// add tableview to main view
view.addSubview(inspectorTableView)
// set constraints for tableview
inspectorTableView.translatesAutoresizingMaskIntoConstraints = false
// inspectorTableView.topAnchor.constraint(equalTo: fakeNavBar.bottomAnchor).isActive = true
inspectorTableView.topAnchor.constraint(equalTo: navBar.bottomAnchor).isActive = true
inspectorTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
inspectorTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
inspectorTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
// allow multiple selection
inspectorTableView.allowsMultipleSelection = true
inspectorTableView.allowsMultipleSelectionDuringEditing = true
// register the inspectorCell
inspectorTableView.register(CheckableTableViewCell.self, forCellReuseIdentifier: "inspectorCell")
}
func setupSearchController() {
// add the bar
searchController.searchResultsUpdater = self
searchController.searchBar.delegate = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search by part name or location"
definesPresentationContext = true
searchController.searchBar.sizeToFit()
self.inspectorTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return filteredParts.count
} else {
return parts.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let inspectorCell = tableView.dequeueReusableCell(withIdentifier: "inspectorCell", for: indexPath)
var content = inspectorCell.defaultContentConfiguration()
var part = Part()
if searching {
// showing the filteredParts array
part = filteredParts[indexPath.row]
if filteredParts[indexPath.row].selected! {
// selected - show checkmark
inspectorCell.accessoryType = .checkmark
} else {
// not selected
inspectorCell.accessoryType = .none
}
} else {
// showing the parts array
part = parts[indexPath.row]
if part.selected! {
// cell selected - show checkmark
inspectorCell.accessoryType = .checkmark
} else {
// not selected
inspectorCell.accessoryType = .none
}
}
content.text = part.title
content.secondaryText = part.location
inspectorCell.contentConfiguration = content
return inspectorCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Note: When you select or unselect a part in the filteredParts array, you must also do so in the parts array
if searching { // using filteredParts array
if filteredParts[indexPath.row].selected! { // selected
filteredParts[indexPath.row].selected = false // unselect the part
// search the parts array for the part by both the title and location, so we for sure get the correct part (there could be parts with identical titles with different locations)
if let part = parts.enumerated().first(where: { $0.element.title == filteredParts[indexPath.row].title && $0.element.location == filteredParts[indexPath.row].location}) { // exact part (with same title & location) found
parts[part.offset].selected = false // unselect the part
}
} else { // not selected
filteredParts[indexPath.row].selected = true // select the part
if let part = parts.enumerated().first(where: { $0.element.title == filteredParts[indexPath.row].title && $0.element.location == filteredParts[indexPath.row].location}) { // exact part (with same title & location) found
parts[part.offset].selected = true // select the part
}
}
} else { // using parts array
if parts[indexPath.row].selected! { // selected
parts[indexPath.row].selected = false // unselect the part
} else { // not selected
parts[indexPath.row].selected = true // select the part
}
}
inspectorTableView.reloadRows(at: [indexPath], with: .none) // reload the tableView
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredParts = parts.filter { ($0.title?.lowercased().prefix(searchText.count))! == searchText.lowercased() }
searching = true
inspectorTableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
inspectorTableView.reloadData()
}
func updateSearchResults(for searchController: UISearchController) {
}
private func updateInspectionTableView() {
NotificationCenter.default.post(name: NSNotification.Name("updateInspectionTable"), object: nil)
}
}
// CHECKABLE UITABLEVIEWCELL
class CheckableTableViewCell: UITableViewCell {
}
I'm trying to implement table view with new DiffableDataSource api, but the cells simply do not load:
var tableView = UITableView()
var currencyPairsArray = [String]()
lazy var fetcher = NetworkDataFetcher()
lazy var searchText = String()
lazy var searchArray = [String]()
lazy var searchController: UISearchController = {
let controller = UISearchController(searchResultsController: nil)
controller.hidesNavigationBarDuringPresentation = false
controller.obscuresBackgroundDuringPresentation = false
controller.searchBar.delegate = self
return controller
}()
fileprivate var dataSource : UITableViewDiffableDataSource<Section, String>!
var searchBarIsEmpty: Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
override func viewDidLoad() {
super.viewDidLoad()
setupVC()
setupTableView()
setupDataSource()
performSearch(with: nil)
fetcher.fetchCurrencyPairs { [weak self] pairsArray in
self?.currencyPairsArray.append(contentsOf: pairsArray)
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
//tableView.reloadData()
// Do any additional setup after loading the view.
}
func setupVC() {
view.backgroundColor = .white
view.addSubview(tableView)
navigationItem.title = "Currency pairs"
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
}
func setupTableView() {
tableView.delegate = self
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.pinToSuperView()
tableView.register(UINib(nibName: "CurrencyPairCell", bundle: nil), forCellReuseIdentifier: CurrencyPairCell.reuseIdentifier)
}
func setupDataSource() {
dataSource = UITableViewDiffableDataSource<Section, String>(tableView: tableView, cellProvider: { [weak self] (tableView, indexPath, _) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: CurrencyPairCell.reuseIdentifier, for: indexPath) as! CurrencyPairCell
cell.delegate = self
let pair = self?.currencyPairsArray[indexPath.row].formattedPair()
cell.currencyPairLabel.text = pair
cell.currencyPair = self?.currencyPairsArray[indexPath.row] ?? ""
return cell
})
}
func performSearch(with filter: String?) {
var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
if let filter = filter {
let filteredPairs = currencyPairsArray.filter {$0.contains(filter)}
snapshot.appendSections([.main])
snapshot.appendItems(filteredPairs, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: true)
} else {
let pairs = currencyPairsArray.sorted()
snapshot.appendSections([.main])
snapshot.appendItems(pairs, toSection: .main)
dataSource.apply(snapshot)
}
}
}
extension CurrencyListViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
performSearch(with: searchText)
}
}
extension CurrencyListViewController {
fileprivate enum Section: Hashable {
case main
}
}
Also, i am getting a warning from the xcode:
[TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window. Table view: ; layer = ; contentOffset: {0, 0}; contentSize: {414, 0}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <TtGC5UIKit29UITableViewDiffableDataSourceOC11FXTMproject26CurrencyListViewControllerP10$107a9eb7c7SectionSS: 0x600002960ca0>>
First of all there is a big design mistake in your code.
With UITableViewDiffableDataSource stop thinking in index paths and data source arrays. Instead think in datasource items.
In setupDataSource you get the model item of the row always from the data source array currencyPairsArray regardless whether you are going to display the filtered data or not. Forget currencyPairsArray and the index path. Take advantage of the third parameter in the closure which represents the item.
func setupDataSource() {
dataSource = UITableViewDiffableDataSource<Section, String>(tableView: tableView, cellProvider: { [weak self] (tableView, _, pair) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: CurrencyPairCell.reuseIdentifier, for: indexPath) as! CurrencyPairCell
cell.delegate = self
cell.currencyPairLabel.text = pair.formattedPair()
cell.currencyPair = pair
return cell
})
}
To get rid of the warning perform the first reload of the data without animation. Add a boolean parameter to performSearch. And rather than checking for nil check for empty string
func performSearch(with filter: String, animatingDifferences: Bool = true) {
var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
let pairs : [String]
if filter.isEmpty {
pairs = currencyPairsArray.sorted()
} else {
pairs = currencyPairsArray.filter {$0.contains(filter)}
}
snapshot.appendSections([.main])
snapshot.appendItems(pairs, toSection: .main)
dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
}
And never call tableView.reloadData() when using UITableViewDiffableDataSource which is most likely the reason of your issue.
Replace
performSearch(with: nil)
fetcher.fetchCurrencyPairs { [weak self] pairsArray in
self?.currencyPairsArray.append(contentsOf: pairsArray)
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
with
fetcher.fetchCurrencyPairs { [weak self] pairsArray in
self?.currencyPairsArray.append(contentsOf: pairsArray)
DispatchQueue.main.async {
self?.performSearch(with: "", animatingDifferences: false)
}
}
Swift 4: I'm using NSNotification post and observe an object between two view controller. My issue is updating the viewController that observes given the received object.
There are two things that needs updating 1. setTitle of a button, 2. the current page on UIPageViewController. How do i update these two things?
I've worked on this the whole day today and yesterday, with no results.
I've tried using struct to do the updating and normal variables.
**YellowViewController - Observes -> Issue here**
let searchedReturnedKey = "Searched"
class YellowViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
let pageView = PageView()
let searched = Notification.Name(rawValue: searchedReturnedKey)
private var isAnimating = false
struct structure {
static var SearchedIndex = Int()
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource = self
delegate = self
setupUIPageView()
setupNavigationBarItem()
createObserver()
}
func createObserver(){
NotificationCenter.default.addObserver(self, selector: #selector(YellowViewController.updateVerseView(notification:)), name: searched, object: nil)
}
#objc func updateVerseView(notification: NSNotification) {
print("Observed")
structure.SearchedIndex = notification.object as! Int
let chapterIndexLabel = doneModel.ChapterIndex
let verseList = doneModel.chapterVerses
let pageView = PageView()
// HERE IS MY ISSUE - booklabel.text and pageview.verses
bookLabel.text = chapterIndexLabel[structure.SearchedIndex]
pageView.verses = verseList[structure.SearchedIndex]
print(structure.SearchedIndex, "Index")
}
func setupUIPageView() {
let verseList = bibleModel.chapterVerses
let chapterIndexLabel = bibleModel.ChapterIndex
let pageViewControllers = [pageView] // Important! UIPageViewController sets ViewController in a list to enable swiping. - Understand this.
pageView.verses = verseList.first! // Important! Setups verses for first view.
bookLabel.text = chapterIndexLabel.first!
setViewControllers(pageViewControllers, direction: .forward, animated: true, completion: nil)
}
var bookLabel = UILabel()
func setupLeftNavItems() {
let bookButton = UIButton(type: .system)
bookButton.setTitle(bookLabel.text! + " 1", for: .normal)
bookButton.setTitleColor(goldColor, for: .normal)
bookButton.titleLabel?.font = UIFont(name: "AvenirNext-DemiBold", size: 18)
bookButton.addTarget(self, action: #selector(handleSearch), for: .touchUpInside)
// bookButton.frame = CGRect(x: 30, y: 0, width: 54, height: 34)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: bookButton)
}
#objc func handleSearch() { // Handles openeing SearchViewController
let searchViewController = SearchViewController()
let navController = UINavigationController(rootViewController: searchViewController)
present(navController, animated: true, completion: nil)
}
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
isAnimating = true
}
// Handles swiping right - To next chapter.
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if isAnimating {
return nil
}
let verseList = bibleModel.chapterVerses
let currentVerseView = (viewController as! PageView).verses
let currentIndex = verseList.index(of: currentVerseView)
let chapterIndexLabel = doneModel.ChapterIndex
if currentIndex! < verseList.count - 1 {
let pageView = PageView()
pageView.verses = verseList[currentIndex! + 1 ]
bookLabel.text = chapterIndexLabel[currentIndex! + 1]
print("Swiped right")
setupLeftNavItems()
createObserver()
return pageView
}
return nil
}
// Handles swiping left - To previous chapter
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if isAnimating {
return nil
}
let verseList = bibleModel.chapterVerses
let currentVerseView = (viewController as! PageView).verses
let currentIndex = verseList.index(of: currentVerseView)
let chapterIndexLabel = doneModel.ChapterIndex
if currentIndex! > 0 {
let pageView = PageView()
pageView.verses = verseList[currentIndex! - 1]
bookLabel.text = chapterIndexLabel[currentIndex! - 1]
setupLeftNavItems()
print("Swiped left")
createObserver()
return pageView
}
return nil
}
}
SearchViewController - Post
class SearchViewController: UITableViewController, UISearchBarDelegate {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleView = navSearchBar
setupView()
}
func setupView() {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
tableView.delegate = self
tableView.dataSource = self
navSearchBar.delegate = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Books.count
}
**I post the data from this function**
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
let cellLabelContent = cell!.textLabel!.text
let cellLabelIndex = Books.firstIndex(of: cellLabelContent!)
print("Book name:", cellLabelContent!, "index:", cellLabelIndex!)
let notificationName = Notification.Name(rawValue: searchedReturnedKey)
NotificationCenter.default.post(name: notificationName, object: cellLabelIndex)
dismiss(animated: true, completion: nil)
}
}
Actual result -> No update
Expected result -> Update given object
To be able to update the current view of your UIPageViewController, you would need to do this inside your updateVerseView. The setViewControllers method is correct and efficient method to update a view inside a UIPageViewController.
let pageViewControllers = [pageView]
pageView.verses = verseList[structure.searchedIndex]
setViewControllers(pageViewControllers, direction: .forward, animated: true, completion: nil)
To update your bookLabel.txt you would just need to call your setupLeftNavItems() function.
Here you need toaddObserver with your selector #selector(YellowViewController.updateVerseView(notification:)
I think you set wrong ViewController name
I am still new to swift and I would ask you for advice. Thank you in advance and sorry for my bad English.
My goal is:
User tap edit button in the table's row. UITextField appears instead cell. After entering value and pressing Return key UITextField disappears again and cell is recalculated.
editButton pressed -> hide priceCell & show UITextField & show keyboard & start editing/entering value (blinking cursor) -> stop editing/entering value execute by pressing Return key -> hide UITextField & shows priceCell & save entered value into array & reload edited row
I use this answer as starting blueprint.
I would like to also use .decimalPad keyboard to easier entering numeric value and limit user to use only numbers (and decimal point), but this exclude use Return key as stop editing, am I right?
I found this possible solution, but it seems to me complex for my problem...
my ViewController:
import UIKit
class PortfolioViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, PortfolioCellDelegate {
let getData = GetData()
...
override func viewDidLoad() {
super.viewDidLoad()
cellTableView.delegate = self
cellTableView.dataSource = self
cellTableView.register(UINib(nibName: "PortfolioCell", bundle: nil), forCellReuseIdentifier: "portfolioCell")
self.currencyControl.selectedSegmentIndex = MyVariables.currencyControlSelected
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let coinCell = tableView.dequeueReusableCell(withIdentifier: "portfolioCell", for: indexPath) as! PortfolioCell
...
coinCell.delegate = self
return coinCell
}
...
func portfolioButtonPressed(coinCell: PortfolioCell) {
let indexPath = self.cellTableView.indexPathForRow(at: coinCell.center)!
let selectedCell = cellTableView.cellForRow(at: indexPath) as! PortfolioCell
selectedCell.priceCell.isHidden = true
selectedCell.textCell.isHidden = false
selectedCell.textCell.delegate = self
func textFieldDidEndEditing(textField: UITextField) {
let owned: Double = Double(textField.text!)!
if owned >= 0 {
MyVariables.dataArray[indexPath.row].ownedCell = owned
} else {
MyVariables.dataArray[indexPath.row].ownedCell = 0.00
}
selectedCell.priceCell.isHidden = false
selectedCell.textCell.isHidden = true
self.cellTableView.reloadData()
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
selectedCell.textCell.resignFirstResponder()
return true
}
}
...
}
my custom cell:
import UIKit
protocol PortfolioCellDelegate {
func portfolioButtonPressed(coinCell: PortfolioCell)
}
class PortfolioCell: UITableViewCell {
var delegate: PortfolioCellDelegate?
...
#IBAction func editCellPressed(_ sender: UIButton) {
delegate?.portfolioButtonPressed(coinCell: self)
}
...
}
For now when button is pressed proper UITextField shows, but don't dismiss after Return key is pressed.
Or should I change it completely and use tap gestures?
To end editing in any kind of scrollView, simply use this
cellTableView.keyboardDismissMode = .onDrag
or
cellTableView.keyboardDismissMode = .interactive
It will hide keyboard when you interact with the tableView
For number keypad you can add toolbar as a textField's inputAccessoryView. On toolbar add cancel button to dismiss keyboard.
There is two way to go:
1.) Delegate
2.) IQKeyboardManager
1.)
Use UITextFieldDelegate
There is one particular callback named "textFieldShouldEndEditing"
In this method, return true.
2.)
User the IQKeyboardManager one liner library. This library manages all the TextFields and scrollviews automatically. You activate it with one line in AppDelegate so it's easy to use.
https://github.com/hackiftekhar/IQKeyboardManager
Working but not as sleek as want it to be and also I was not capable to make IQKeyboardManager works so I did use inputAccessoryView.
custom cell:
import UIKit
protocol PortfolioCellDelegate {
func portfolioButtonPressed(didSelect coinCell: PortfolioCell)
func portfolioButtonPressed(coinCell:PortfolioCell, editingChangedInTextCell newValue:String)
}
class PortfolioCell: UITableViewCell, UITextFieldDelegate {
var delegate: PortfolioCellDelegate?
...
#IBAction func editCellPressed(_ sender: UIButton) {
textCell.becomeFirstResponder()
delegate?.portfolioButtonPressed(didSelect: self)
}
#IBAction func textCellValueChanged(_ sender: UITextField) {
if (sender.text?.isEmpty)! {
delegate?.portfolioButtonPressed(coinCell: self, editingChangedInTextCell: "XXX")
} else {
let text = sender.text
delegate?.portfolioButtonPressed(coinCell: self, editingChangedInTextCell: text!)
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.textCell.delegate = self
let flexiableSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(self.doneButtonAction))
let toolBar:UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: 35))
toolBar.barTintColor = UIColor(red:0.15, green:0.69, blue:0.75, alpha:1.0)
toolBar.tintColor = UIColor(red:0.93, green:0.93, blue:0.93, alpha:1.0)
toolBar.setItems([flexiableSpace, doneButton], animated: false)
textCell.inputAccessoryView = toolBar
textCell.keyboardType = UIKeyboardType.decimalPad
}
#objc func doneButtonAction() {
textCell.endEditing(true)
}
...
}
ViewController:
import UIKit
class PortfolioViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, PortfolioCellDelegate {
let getData = GetData()
...
override func viewDidLoad() {
super.viewDidLoad()
cellTableView.delegate = self
cellTableView.dataSource = self
cellTableView.register(UINib(nibName: "PortfolioCell", bundle: nil), forCellReuseIdentifier: "portfolioCell")
self.currencyControl.selectedSegmentIndex = MyVariables.currencyControlSelected
getData.delegate = self
timeStampLabel.text = MyVariables.timeStamp
}
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.cellTableView.reloadData()
self.currencyControl.selectedSegmentIndex = MyVariables.currencyControlSelected
self.timeStampLabel.text = MyVariables.timeStamp
}
//MARK: - tableView
/***************************************************************/
...
func portfolioButtonPressed(coinCell: PortfolioCell, editingChangedInTextCell newValue: String) {
let indexPath = self.cellTableView.indexPathForRow(at: coinCell.center)!
let selectedCell = cellTableView.cellForRow(at: indexPath) as! PortfolioCell
selectedCell.priceCell.isHidden = false
selectedCell.textCell.isHidden = true
if newValue != "XXX" {
let owned: Double = Double(newValue)!
MyVariables.dataArray[indexPath.row].ownedCell = owned
}
selectedCell.priceCell.isHidden = false
selectedCell.textCell.isHidden = true
self.cellTableView.reloadRows(at: [indexPath], with: .automatic)
}
func portfolioButtonPressed(didSelect coinCell: PortfolioCell) {
let indexPath = self.cellTableView.indexPathForRow(at: coinCell.center)!
let selectedCell = cellTableView.cellForRow(at: indexPath) as! PortfolioCell
selectedCell.priceCell.isHidden = true
selectedCell.textCell.isHidden = false
}
...
}
It's easy: You should select that table view cell, then enable User Interaction Enabled in the attribute inspector.
code of search controller
it's working fine for searching
issue 1:
when I scroll tableView, I want to show search controller along with table view, search controller also gets scrolled with table view.
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.dimsBackgroundDuringPresentation = false
tableView.tableHeaderView = searchController.searchBar
searchController.delegate = self
searchController.searchBar.sizeToFit()
self.searchController.searchBar.delegate = self
tableView.tableHeaderView = nil
definesPresentationContext = true
}
update data of searching :
func updateSearchResults(for searchController: UISearchController) {
_ = kidsData
let searchToSearch = searchController.searchBar.text
if(searchToSearch == "")
{
self.kidsData = self.KidsDataDuplicate
}
else{
self.kidsData.removeAll()
let itemsarray = self.KidsDataDuplicate
var forkidsinArray = [String]()
for Kids in itemsarray {
forkidsinArray.append(Kids.name)
if(Kids.name.range(of: searchToSearch!, options: .caseInsensitive) != nil)
{
self.kidsData.append(Kids)
}
}
}
self.tableView.reloadData()
}
issue 2 :
Tableview navigation bar contains search button, when I click on search button at navigation bar, search controller should show its working at tableview header, but after scrolling tableview I want to show search controller at tableview starting cell.
I can try the scroll delegates it's not working for me
pls help me......!
this is code of search button at navigation
var launchBool: Bool = false {
didSet {
if launchBool == true {
Status = 1
tableView.tableHeaderView = searchController.searchBar
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .middle, animated: true)
} else {
tableView.tableHeaderView = nil
myInt = 0
}
}
}
#IBAction func NAVSearchButton(_ sender: UIBarButtonItem) {
launchBool = !launchBool
}