Configured a searcher in the navigation bar in a UITable. Everything is working fine, accept the fact that when I searched and found the needed cells and I want to click on that cell, the search term is quickly removed from the search bar. The result is that I get back the "old" table. I can not use the search results.
Class property: UITableViewController, ExpandableHeaderViewDelegate, UISearchBarDelegate, UISearchResultsUpdating {
var filteredArray = [Mijnproducten]()
var shouldShowSearchResults = false
override func viewDidLoad() {
super.viewDidLoad()
configureSearchController()
}
func configureSearchController() {
// Initialize and perform a minimum configuration to the search controller.
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = true
searchController.searchBar.placeholder = "Search here..."
searchController.searchBar.sizeToFit()
searchController.hidesNavigationBarDuringPresentation = false
// Place the search bar view to the tableview headerview.
self.navigationItem.titleView = searchController.searchBar
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
shouldShowSearchResults = true
searchWasCancelled = false
self.tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
shouldShowSearchResults = false
searchWasCancelled = true
self.tableView.reloadData()
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
var searchTerm = ""
if searchWasCancelled {
searchController.searchBar.text = searchTerm
}
else {
searchTerm = searchController.searchBar.text!
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let text = searchController.searchBar.text
searchController.searchBar.text = text
if !shouldShowSearchResults {
shouldShowSearchResults = false
self.tableView.reloadData()
}
searchController.searchBar.resignFirstResponder()
}
func updateSearchResults(for searchController: UISearchController) {
let searchtext = searchController.searchBar.text
print(searchtext)
filteredArray = mijnproducten01.filter{ product in
return product.productname.lowercased().contains((searchtext?.lowercased())!)
}
print(filteredArray)
if searchtext?.isEmpty == false
{ shouldShowSearchResults = true }
else
{ shouldShowSearchResults = false }
// Reload the tableview.
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!) as! RowTableViewCell
let RowName = currentCell.ProductLine!.text
let temp = currentCell.UUID!.text
print("jaaaa", temp)
TAGID = Int(temp!)!
if RowName == "History"
{
tableView.deselectRow(at: indexPath!, animated: true)
self.performSegue(withIdentifier: "PropertyToHistory", sender: self)
}
else if RowName == "Description"
{
tableView.deselectRow(at: indexPath!, animated: true)
self.performSegue(withIdentifier: "PropertyToDescription", sender: self)
}
else if RowName == "Transfer"
{
tableView.deselectRow(at: indexPath!, animated: true)
self.performSegue(withIdentifier: "PropertyToTransfer", sender: self)
}
}
I would suggest you to put breakpoints on your searchBarTextDidBeginEditing,searchBarCancelButtonClicked,searchBarTextDidEndEditing,searchBarSearchButtonClicked and updateSearchResults.
When you select the cell and search result disappears then see where the breakpoint stops.
It seems that there could be logic issues with shouldShowSearchResults and searchWasCancelled.
Because from what you are saying is correct then somehow your searchController.searchBar.resignFirstResponder() is triggered which cancels the search. Putting up breakpoints and debugger will get you the culprit.
Related
I have a searchBar with a cancel button. When I click on cancel button it doesn't reset the searchBar to its initial state.
Here is the full source code.
var searchBar: UISearchBar = UISearchBar()
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBarText = searchBar.text?.lowercased()
searchBarScope = searchBar.selectedScopeButtonIndex
showList()
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(true, animated: true)
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = nil
searchBar.setShowsCancelButton(false, animated: true)
searchBar.endEditing(true)
}
public func setupSearchBarStyle() {
UISearchBar.appearance().searchBarStyle = .minimal
UISearchBar.appearance().backgroundColor = UIColor.white
UISearchBar.appearance().barTintColor = UIColor.white
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsScopeBar = true
if (navigationItem.title != nil) {
self.searchBar.scopeButtonTitles = [String(format: "gesamte %#", ci("project_s")), String(format: "in %#", navigationItem.title!)]
}
}
override func viewDidLayoutSubviews() {
self.searchBar.sizeToFit()
}
public override func viewDidLoad() {
self.navigationController?.setNavigationBarHidden(false, animated: false)
navigationItem.title = navigationItem.title ?? ci("plan_p")
guard let projectId = GlobalState.selectedProjectId, let byProject : Results<Structure> = self.by(projectId: projectId) else {
return
}
//search bar
tableView.rowHeight = 100.0
tableView.tableHeaderView = searchBar
self.searchBar.showsCancelButton = true
self.searchBar.sizeToFit()
self.definesPresentationContext = true
self.searchBar.delegate = self
tableView.allowsMultipleSelectionDuringEditing = true
How can I change the searchBar to its initial state after the user clicks on the cancel button? Right now it changes the searchText to nil after the user clicks on cancel.
In the searchBarCancelButtonClicked func:
searchBar.text = ""
searchBar.showsCancelButton = false
Also in thetextDidChange :
yourSearchBar.showsCancelButton = true
I think its because of this code:
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchBar.setShowsCancelButton(true, animated: true)
}
It has to be :
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
}
I am making an app in which i have a home screen which lists categories and store data into tableview. in tableview i have a search button which navigates me to search screen when clicked and on search screen i have taken custom textfield to search. Now i want that when i search something and it shows in result then when i click on searched result then it should show data of the category or store selected on previous home screen. And the search result is category data and store data. All data is coming from api and am using tableview to show search data
screenshot for coupons api in which search data will be display:
screenshot for search api:
code for my search screen is as below:
class SearchPageController: UIViewController {
#IBOutlet weak var searchTxtBar: UITextField!
#IBOutlet weak var searchTblView: UITableView!
var searchData = [ModelSearched]()
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
// Do any additional setup after loading the view.
searchTxtBar.delegate = self
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
//MARK: IBActions
#IBAction func toHomeScreen(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
func getSearchList(){
let params: Parameters=[
"search":searchTxtBar.text!,
]
if ApiUtillity.sharedInstance.isReachable()
{
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseSearchList>().API_GET(Url: SD_GET_SearchList, Params: params as [String:AnyObject], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
self.searchData.removeAll()
let resul_array_tmp_new = modelResponse.searched! as NSArray
if resul_array_tmp_new.count > 0 {
for i in modelResponse.searched! {
self.searchData.append(i)
}
}
}
else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.searchTblView.reloadData()
}) { (failed) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.view.makeToast(failed.localizedDescription)
}
}
else
{
self.view.makeToast("No Internet Connection..")
}
}
#IBAction func clearSearchData(_ sender: UIButton) {
self.searchData.removeAll()
self.searchTxtBar.text = ""
searchTblView.reloadData()
}
}
//MARK: Tableview delegates and datasource methods
extension SearchPageController: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "catstoredata")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "catstoredata")
}
let dict = searchData[indexPath.row]
cell?.selectionStyle = .none
cell?.textLabel?.text = dict.name
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
self.navigationController?.popViewController(animated: true)
}
}
//MARK: textfield delegates method
extension SearchPageController: UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.searchTxtBar.resignFirstResponder()
self.searchTblView.reloadData()
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
self.getSearchList()
}
}
code for my home screen is as below:
class HomeViewController: UIViewController {
var couponsData = [ModelCoupons]()
var colorList = [UIColor]()
var selectedIds = [Int]()
#IBOutlet var logoutPopup: UIView!
#IBOutlet weak var homeTblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//append colors
colorList.append(UIColor(rgb: 0xdd191d))
colorList.append(UIColor(rgb: 0xd81b60))
colorList.append(UIColor(rgb: 0x8e24aa))
colorList.append(UIColor(rgb: 0x5e35b1))
colorList.append(UIColor(rgb: 0x3949ab))
colorList.append(UIColor(rgb: 0x4e6cef))
colorList.append(UIColor(rgb: 0x00acc1))
colorList.append(UIColor(rgb: 0x00897b))
colorList.append(UIColor(rgb: 0x0a8f08))
colorList.append(UIColor(rgb: 0x7cb342))
colorList.append(UIColor(rgb: 0xc0ca33))
colorList.append(UIColor(rgb: 0xfdd835))
colorList.append(UIColor(rgb: 0xfb8c00))
colorList.append(UIColor(rgb: 0xf4511e))
colorList.append(UIColor(rgb: 0xf4511e))
colorList.append(UIColor(rgb: 0x757575))
colorList.append(UIColor(rgb: 0x546e7a))
self.homeTblView.register(UINib(nibName: "HomeCell", bundle: nil), forCellReuseIdentifier: "HomeCell")
self.homeTblView.register(UINib(nibName: "Home1Cell", bundle: nil), forCellReuseIdentifier: "Home1Cell")
self.post_CouponsData()
self.homeTblView.reloadData()
print(selectedIds)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
func changeDateForamte(dateString: String, currentDateFormate: String, newDateFormate: String) -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = currentDateFormate
let newDate = dateFormatter.date(from: dateString)
dateFormatter.dateFormat = newDateFormate
return dateFormatter.string(from: newDate!)
}
#IBAction func logout_yes(_ sender: Any) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.navigationController?.pushViewController(vc, animated: true)
}
#IBAction func logout_no(_ sender: Any) {
self.logoutPopup.removeFromSuperview()
}
#objc func openDeals(sender: UIButton) {
let svc = SFSafariViewController(url: URL(string: couponsData[sender.tag].guid!)!)
self.present(svc, animated: true, completion: nil)
}
//MARK: IBActions
#IBAction func toCategoryScreen(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func toSearchPage(_ sender: UIButtonX) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SearchPageController") as! SearchPageController
self.navigationController?.pushViewController(vc, animated: true)
}
#IBAction func logoutBtnPressed(_ sender: Any) {
ApiUtillity.sharedInstance.AddSubViewtoParentView(parentview: self.view, subview: logoutPopup)
}
func post_CouponsData() {
if ApiUtillity.sharedInstance.isReachable() {
var params = [String : String]()
params ["term_ids"] = "\(self.selectedIds.map(String.init).joined(separator: ","))"
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseCouponsList>().API_POST(Url: SD_POST_CouponsList, Params: params as [String:AnyObject], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
ApiUtillity.sharedInstance.StopProgress(view: self.view)
let dict = modelResponse.coupons
for i in dict! {
self.couponsData.append(i)
}
}else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.homeTblView.reloadData()
}) { (failed) in
self.view.makeToast(failed.localizedDescription)
ApiUtillity.sharedInstance.StopProgress(view: self.view)
}
}else {
self.view.makeToast("No internet connection...")
ApiUtillity.sharedInstance.StopProgress(view: self.view)
}
}
}
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return couponsData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if !couponsData[indexPath.row].postImage!.isEmpty {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell", for: indexPath) as! HomeCell
let dict = couponsData[indexPath.row]
if let postTitle = dict.postTitle, postTitle.count != 0 {
cell.ticket_postTitle.text = postTitle
}
if let postContent = dict.postContent, postContent.count != 0 {
cell.ticket_postContent.text = postContent
}
if let storeName = dict.stores, storeName.count != 0 {
cell.storename.text = storeName
}
cell.home_image.image = UIImage(named: dict.postImage!)
cell.ticketImageView.tintColor = colorList[indexPath.row]
cell.ticket_ValidDate.text = self.changeDateForamte(dateString: dict.validTill!, currentDateFormate: "yyyy-MM-dd", newDateFormate: "dd MMMM yyyy")
// cell.ticketImageView.tintColor = .random()
cell.goToDealBtn.tag = indexPath.row
cell.goToDealBtn.addTarget(self, action: #selector(self.openDeals), for: .touchUpInside)
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: "Home1Cell", for: indexPath) as! Home1Cell
let dict = couponsData[indexPath.row]
if let postTitle = dict.postTitle, postTitle.count != 0 {
cell.ticket_postTitle.text = postTitle
}
if let postContent = dict.postContent, postContent.count != 0 {
cell.ticket_postContent.text = postContent
}
if let storeName = dict.stores, storeName.count != 0 {
cell.storename.text = storeName
}
cell.ticketImageView.tintColor = colorList[indexPath.row]
cell.ticket_ValidDate.text = self.changeDateForamte(dateString: dict.validTill!, currentDateFormate: "yyyy-MM-dd", newDateFormate: "dd MMMM yyyy")
// cell.ticketImageView.tintColor = .random()
cell.goToDealBtn.tag = indexPath.row
cell.goToDealBtn.addTarget(self, action: #selector(self.openDeals), for: .touchUpInside)
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if !couponsData[indexPath.row].postImage!.isEmpty {
return 339.0
}else {
return 234.0
}
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if !couponsData[indexPath.row].postImage!.isEmpty {
return 339.0
}else {
return 234.0
}
}
}
I am creating an app in which i have a controller in which i have a tableview which will show data from previous screen when cell from c ategory section or cell from store section are selected or only one is selected then when i click the double arrow button shown in app then it should navigate to tableview screen and should show all the data from category or store or both into tableview. in tableview controller i have an API which is POST and has a body parameter of 'term_ids' which contains value as 556,574 which is comma seperated means the former one is for category and latter one is for store or both ids contains category data or store data. Means i have to pass two ids and make them comma seperated and then pass to tableview controller
lets say in category screenshot i have selected first two cells and when i tap on double arrow button the selected cell data should pass to another screen whose screenshot is as below:
api link for category data: https://api.myjson.com/bins/wggld
api link for store data: https://api.myjson.com/bins/1fc46p
api link for coupons which i need to populate into tableview based on ID from category and store api link: https://api.myjson.com/bins/1c4dip
my app screenshot for better understanding:
code for my category screen and main home view screen where i want to populate data is as below:
code for categoryViewController is as below:
class CategoryViewController: UIViewController {
//MARK: IBOutlets
#IBOutlet weak var store_bar: UIViewX!
#IBOutlet weak var store_title: UIButton!
#IBOutlet weak var category_title: UIButton!
#IBOutlet weak var category_bar: UIViewX!
#IBOutlet weak var categoryColView: UICollectionView!
var selectedBtnIndex:Int = 1
var selectedIndexPaths = [Int]()
var tempStoreIndexPaths = [Int]()
var categoryData = [ModelCategories]()
var storeData = [ModelStore]()
var arrCategoryImages = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
// register collectionview cell
self.categoryColView.register(UINib(nibName: "CategoryCell1", bundle: nil), forCellWithReuseIdentifier: "CategoryCell1")
self.categoryColView.register(UINib(nibName: "StoresCell", bundle: nil), forCellWithReuseIdentifier: "StoresCell")
self.store_bar.isHidden = true
self.getCategoriesList()
self.getStoreList()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
#objc func click_Category(sender: UIButton!) {
if sender.isSelected == true {
selectedIndexPaths.append(sender.tag)
sender.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
sender.isSelected = false
}else {
selectedIndexPaths = selectedIndexPaths.filter{ $0 != sender.tag }
sender.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
sender.isSelected = true
}
}
#objc func click_store(sender: UIButton!) {
if sender.isSelected == true {
tempStoreIndexPaths.append(sender.tag)
sender.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
sender.isSelected = false
}else {
tempStoreIndexPaths = tempStoreIndexPaths.filter{ $0 != sender.tag }
sender.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
sender.isSelected = true
}
}
//MARK: IBActions
#IBAction func categoriesData(_ sender: UIButton) {
selectedBtnIndex = 1
self.categoryColView.isHidden = false
self.store_bar.isHidden = true
self.category_title.setTitleColor(UIColor.black, for: .normal)
self.category_bar.isHidden = false
self.store_title.setTitleColor(UIColor(rgb: 0xAAAAAA), for: .normal)
self.categoryColView.reloadData()
}
#IBAction func storeData(_ sender: UIButton) {
selectedBtnIndex = 2
self.categoryColView.isHidden = false
self.store_bar.isHidden = false
self.store_title.setTitleColor(UIColor.black, for: .normal)
self.category_bar.isHidden = true
self.category_title.setTitleColor(UIColor(rgb: 0xAAAAAA), for: .normal)
self.categoryColView.reloadData()
}
#IBAction func showHomeScreen(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
if selectedBtnIndex == 1 {
vc.couponId = categoryData[sender.tag].ID!
}else {
vc.couponId = storeData[sender.tag].ID!
}
self.navigationController?.pushViewController(vc, animated:true)
}
#IBAction func toSearchPage(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SearchPageController") as! SearchPageController
self.navigationController?.pushViewController(vc, animated:true)
}
func getCategoriesList() {
if ApiUtillity.sharedInstance.isReachable() {
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseCategoryList>().API_GET(Url: SD_GET_CategoriesList, Params: [:], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
self.categoryData.removeAll()
let resul_array_tmp_new = modelResponse.categories! as NSArray
if resul_array_tmp_new.count > 0 {
for i in modelResponse.categories! {
if i.count != 0 {
if let image = UIImage(named: "\(i.slug!.uppercased())") {
self.arrCategoryImages.append(image)
self.categoryData.append(i)
}else {
self.arrCategoryImages.append(UIImage(named: "tickets")!)
self.categoryData.append(i)
}
}
}
}
}
else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.categoryColView.reloadData()
}) { (failed) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.view.makeToast(failed.localizedDescription)
}
}
else
{
self.view.makeToast("No Internet Connection..")
}
}
func getStoreList() {
if ApiUtillity.sharedInstance.isReachable() {
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseStoreList>().API_GET(Url: SD_GET_StoreList, Params: [:], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
self.storeData.removeAll()
let resul_array_tmp_new = modelResponse.store! as NSArray
if resul_array_tmp_new.count > 0 {
for i in modelResponse.store! {
if i.count != 0 {
self.storeData.append(i)
}
}
}
}
else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.categoryColView.reloadData()
}) { (failed) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.view.makeToast(failed.localizedDescription)
}
}
else
{
self.view.makeToast("No Internet Connection..")
}
}
}
//MARK: Delegate and Data Source Methods
extension CategoryViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if selectedBtnIndex == 1{
return categoryData.count
}else {
return storeData.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if selectedBtnIndex == 1{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoryCell1", for: indexPath) as! CategoryCell1
let dict = categoryData[indexPath.row]
if let catName = dict.name, catName.count != 0 {
cell.categoryName.text = catName
}
if let catOffersCount = dict.count {
if catOffersCount == 1 {
cell.catOfferCount.text = "\(catOffersCount)"+" "+"Offer"
}else {
cell.catOfferCount.text = "\(catOffersCount)"+" "+"Offers"
}
}
cell.categoryImage.image = arrCategoryImages[indexPath.row]
cell.btn_click.tag = indexPath.row
cell.btn_click.addTarget(self, action: #selector(self.click_Category), for: .touchUpInside)
if selectedIndexPaths.contains(indexPath.row) {
cell.btn_click.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
cell.btn_click.isSelected = true
}else {
cell.btn_click.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
cell.btn_click.isSelected = false
}
return cell
}else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StoresCell", for: indexPath) as! StoresCell
let dict = storeData[indexPath.row]
if let storeName = dict.name, storeName.count != 0 {
cell.storeName.text = storeName
}
if let storeOfferCount = dict.count {
cell.storeOfferCount.text = "\(storeOfferCount)"+" "+"Offers"
}
cell.store_btn_click.tag = indexPath.row
cell.store_btn_click.addTarget(self, action: #selector(self.click_store), for: .touchUpInside)
if tempStoreIndexPaths.contains(indexPath.row) {
cell.store_btn_click.setImage(#imageLiteral(resourceName: "image_checked"), for: .normal)
cell.store_btn_click.isSelected = true
}else {
cell.store_btn_click.setImage(#imageLiteral(resourceName: "image_unchecked"), for: .normal)
cell.store_btn_click.isSelected = false
}
return cell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if selectedBtnIndex == 1{
return CGSize(width: (UIScreen.main.bounds.width) / 3, height: 93)
}else {
return CGSize(width: (UIScreen.main.bounds.width) / 2, height: 48)
}
}
code for homeView COntroller is as below:
import UIKit
class HomeViewController: UIViewController {
var couponsData = [ModelCoupons]()
var couponId = Int()
#IBOutlet weak var homeTblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.homeTblView.register(UINib(nibName: "HomeCell", bundle: nil), forCellReuseIdentifier: "HomeCell")
self.post_CouponsData()
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
//MARK: IBActions
#IBAction func toCategoryScreen(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func toSearchPage(_ sender: UIButtonX) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SearchPageController") as! SearchPageController
self.navigationController?.pushViewController(vc, animated: true)
}
func post_CouponsData() {
if ApiUtillity.sharedInstance.isReachable() {
var params = [String : String]()
params ["term_ids"] = "\(self.couponId)"
ApiUtillity.sharedInstance.StartProgress(view: self.view)
APIClient<ModelBaseCouponsList>().API_POST(Url: SD_POST_CouponsList, Params: params as [String:AnyObject], Authentication: true, Progress: true, Alert: true, Offline: false, SuperVC: self, completionSuccess: { (modelResponse) in
ApiUtillity.sharedInstance.StopProgress(view: self.view)
if(modelResponse.success == true) {
ApiUtillity.sharedInstance.StopProgress(view: self.view)
let dict = modelResponse.coupons
for i in dict! {
self.couponsData.append(i)
}
}else {
self.view.makeToast(modelResponse.message)
}
ApiUtillity.sharedInstance.StopProgress(view: self.view)
self.homeTblView.reloadData()
}) { (failed) in
self.view.makeToast(failed.localizedDescription)
ApiUtillity.sharedInstance.StopProgress(view: self.view)
}
}else {
self.view.makeToast("No internet connection...")
ApiUtillity.sharedInstance.StopProgress(view: self.view)
}
}
}
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return couponsData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell", for: indexPath) as! HomeCell
let dict = couponsData[indexPath.row]
if let postTitle = dict.postTitle, postTitle.count != 0 {
cell.ticket_postTitle.text = postTitle
}
if let postContent = dict.postContent, postContent.count != 0 {
cell.ticket_postContent.text = postContent
}
if let storeName = dict.stores, storeName.count != 0 {
cell.storename.text = storeName
}
let dateFormatterGet = DateFormatter()
dateFormatterGet.dateFormat = "yyyy-MM-dd"
let dateFormatterPrint = DateFormatter()
dateFormatterPrint.dateFormat = "dd MMMM yyyy"
let datee = ApiUtillity.sharedInstance.ConvertStingTodate(forApp: dict.validTill!)
cell.ticket_ValidDate.text = dateFormatterPrint.string(from: datee)
cell.ticketImageView.tintColor = .random()
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 339.0
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 339.0
}
}
recently in the search VC of my app I have been having a major problem with the contraints for weeks. I've redone them 4 times now with no improvement. My tableview cell is not complex -- an imageView located at the left and two labels on top of each other. Most cells size fine. The only thing is that(without pattern) two cells are randomly messed up(the labels and imageView move way out of place). You can see here:
Here is a picture of the constraints for the vc:
The strange thing is that this sometimes occurs when I toggle the scopeButtons up top. I looked in my code to see if I could fix this when the scopeButton reloads the tableview, but I could not find a problematic instance. My code is below:
import UIKit
import Firebase
import Kingfisher
class SearchPostsController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
var idArray:[String] = []
var detailViewController: DetailViewController? = nil
var candies = [Person]()
var filteredCandies = [Person]()
let searchController = UISearchController(searchResultsController: nil)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = false
//initiate the search bar that appears up top when view is segued to
}
if let selectionIndexPath = self.tableView.indexPathForSelectedRow {
self.tableView.deselectRow(at: selectionIndexPath, animated: animated)
}
self.tableView.reloadData()
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if #available(iOS 11.0, *) {
navigationItem.hidesSearchBarWhenScrolling = true
}
}
override func viewDidLoad() {
super.viewDidLoad()
Database.database().reference()
.child("\(UserData().mySchool!)/posts")
.queryOrderedByKey()//keys were out of order, so we have to use this to help
.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
for child in snapshot.children.allObjects as! [DataSnapshot] {
print(child.key)
self.idArray.append(child.key)
}
var reversedNames = [String]()
for arrayIndex in 0..<self.idArray.count {
reversedNames.append(self.idArray[(self.idArray.count - 1) - arrayIndex])
//reverse names so we dont have to sort the cells by date
}
for x in reversedNames{
self.searchNames(id: x)//get names from the ids here, tada!!!
self.tableView.reloadData()
}
})
//self.tableView.reloadData()//without this, the results wouldnt show up right away
searchController.searchBar.setScopeBarButtonTitleTextAttributes([NSAttributedStringKey.foregroundColor.rawValue: UIColor.white], for: .normal)
searchController.searchBar.scopeButtonTitles = ["Posts", "Users"]
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search posts or usernames"
searchController.searchBar.showsScopeBar = true
navigationItem.searchController = searchController
definesPresentationContext = true
if let splitViewController = splitViewController {
let controllers = splitViewController.viewControllers
detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 74
}
// override func viewWillDisappear(_ animated: Bool) {
// candies.removeAll()
// }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DAY69:GRADUATION DAY", for: indexPath) as! SeachCell
cell.cellImageVIew.frame.size.width = 48
cell.cellImageVIew.frame.size.height = 48
let personUser: Person
if isFiltering() {
personUser = filteredCandies[indexPath.row]
} else {
personUser = candies[indexPath.row]
}
//PERSON USER IS IMPORTANT!!!!! ^^^
cell.nameLabel.text = personUser.name.removingPercentEncoding
cell.messageLabel.text = personUser.category.removingPercentEncoding
let name = personUser.name
Database.database().reference().child("users/\(name)/profileImageURL").observe(.value, with: { (snapshot) in
let profURL = "\(snapshot.value!)"
let profIRL = URL(string: profURL)
//set up imageview
cell.cellImageVIew.layer.borderWidth = 1
cell.cellImageVIew.layer.masksToBounds = false
cell.cellImageVIew.layer.borderColor = UIColor.black.cgColor
cell.cellImageVIew.layer.cornerRadius = cell.cellImageVIew.frame.height/2
cell.cellImageVIew.clipsToBounds = true
cell.cellImageVIew.contentMode = .scaleAspectFill
cell.cellImageVIew.kf.indicatorType = .activity
cell.cellImageVIew.kf.setImage(with: profIRL)
})
//TODO: make an extension of imageview to do all this for me. It's getting to be ridiculous
return cell
}
func searchNames(id: String){
// var message = String()
// var name = String()
Database.database().reference().child("\(UserData().mySchool!)/posts/\(id)/message").observe(.value, with: { (snapshot) in
// message = snapshot.value as! String
Database.database().reference().child("\(UserData().mySchool!)/posts").child("\(id)/username").observe(.value, with: { (username) in
// name = username.value as! String
let user = Person(category: "\(snapshot.value!)", name: "\(username.value!)", id: id)
self.candies.append(user)
print( "\(snapshot.value!)", "\(username.value!)")
self.tableView.reloadData()
})
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isFiltering() {
return filteredCandies.count
}
return candies.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
tableView.estimatedRowHeight = 74.0
tableView.rowHeight = UITableViewAutomaticDimension
return UITableViewAutomaticDimension
}
// func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
// return 74
// }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "DAY69:GRADUATION DAY", for: indexPath) as! SeachCell
cell.cellImageVIew.frame.size.width = 48
cell.cellImageVIew.frame.size.height = 48
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles?[searchBar.selectedScopeButtonIndex]
if scope == "Users"{
let username = candies[indexPath.row].name
print(username)
self.tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "userClicked", sender: username)
}
if scope == "Posts"{
let post = candies[indexPath.row].category
let user = candies[indexPath.row].name
let id = candies[indexPath.row].id
print(post)
let defaults = UserDefaults.standard
defaults.set(id, forKey: "ID")
let def2 = UserDefaults.standard
def2.set(post, forKey: "Post")
def2.set(user, forKey: "USER")
self.tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "postCellTapped", sender: nil)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
//__________tbv methods above________________________________________________
func searchBarIsEmpty() -> Bool {
// Returns true if the text is empty or nil
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredCandies = candies.filter({(candy : Person) -> Bool in
let doesCategoryMatch = (scope == "Posts") || (scope == "Users")
print(searchText)
if searchBarIsEmpty() {
return doesCategoryMatch
}
if scope == "Users"{
return doesCategoryMatch && candy.name.lowercased().contains(searchText.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!.lowercased())
}
else{
return doesCategoryMatch && candy.category.lowercased().contains(searchText.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!.lowercased())
}
})
tableView.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let personalUser: Person
if isFiltering() {
personalUser = filteredCandies[indexPath.row]
} else {
personalUser = candies[indexPath.row]
}
}
}
if segue.identifier == "userClicked" {
if let nextView = segue.destination as? UserProfileController {
nextView.selectedUser = "\(sender!)"
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func isFiltering() -> Bool {
let searchBarScopeIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
return searchController.isActive && (!searchBarIsEmpty() || searchBarScopeIsFiltering)
}
}
extension SearchPostsController: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: scope)
}
}
extension SearchPostsController: UISearchBarDelegate {
// MARK: - UISearchBar Delegate
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
}
}
Any help would be greatly appreciated in trying to fix the constraints! Thanks!
My goal is to search for a string and then go to it. I have these three lines of code needed to implement it. I just know my thought process for getting there is missing something. I am not sure how to use .findstring. I read that it returns an array of PDFSelections. But I am not sure how to use that to use .setCurrentSelection using the PDFSelection array.
let found = document.findString(selection, withOptions: .caseInsensitive)
let stringSelection = page?.selection(for: NSRange(location:10, length:5))
pdfView.setCurrentSelection(stringSelection, animate: true)
Create SearchTableViewController ViewController :
import UIKit
import PDFKit
protocol SearchTableViewControllerDelegate: class {
func searchTableViewController(_ searchTableViewController: SearchTableViewController, didSelectSerchResult selection: PDFSelection)
}
class SearchTableViewController: UITableViewController {
open var pdfDocument: PDFDocument?
weak var delegate: SearchTableViewControllerDelegate?
var searchBar = UISearchBar()
var searchResults = [PDFSelection]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 150
searchBar.delegate = self
searchBar.showsCancelButton = true
searchBar.searchBarStyle = .minimal
navigationItem.titleView = searchBar
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(closeBtnClick))
tableView.register(UINib(nibName: "SearchViewCell", bundle: nil), forCellReuseIdentifier: "SearchViewCell")
}
#objc func closeBtnClick(sender: UIBarButtonItem) {
dismiss(animated: false, completion: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
searchBar.becomeFirstResponder()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return searchResults.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchViewCell", for: indexPath) as! SearchViewCell
let selection = searchResults[indexPath.row]
let page = selection.pages[0]
let outline = pdfDocument?.outlineItem(for: selection)
let outlintstr = outline?.label ?? ""
let pagestr = page.label ?? ""
let txt = outlintstr + " 页码: " + pagestr
cell.destinationLabel.text = ""
let extendSelection = selection.copy() as! PDFSelection
extendSelection.extend(atStart: 10)
extendSelection.extend(atEnd: 90)
extendSelection.extendForLineBoundaries()
let range = (extendSelection.string! as NSString).range(of: selection.string!, options: .caseInsensitive)
let attrstr = NSMutableAttributedString(string: extendSelection.string!)
attrstr.addAttribute(NSAttributedStringKey.backgroundColor, value: UIColor.yellow, range: range)
cell.resultTextLabel.attributedText = attrstr
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selection = searchResults[indexPath.row]
delegate?.searchTableViewController(self, didSelectSerchResult: selection)
dismiss(animated: false, completion: nil)
}
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
searchBar.resignFirstResponder()
}
}
extension SearchTableViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
pdfDocument?.cancelFindString()
dismiss(animated: false, completion: nil)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// if searchText.count < 2 {
// return
// }
searchResults.removeAll()
tableView.reloadData()
pdfDocument?.cancelFindString()
pdfDocument?.delegate = self
pdfDocument?.beginFindString(searchText, withOptions: .caseInsensitive)
}
}
extension SearchTableViewController: PDFDocumentDelegate {
func didMatchString(_ instance: PDFSelection) {
searchResults.append(instance)
tableView.reloadData()
}
}
On Search Button Tap :
let searchViewController = SearchTableViewController()
searchViewController.pdfDocument = self.pdfdocument
searchViewController.delegate = self
let nav = UINavigationController(rootViewController: searchViewController)
self.present(nav, animated: false, completion:nil)
You will get highlighted text in :
func searchTableViewController(_ searchTableViewController: SearchTableViewController, didSelectSerchResult selection: PDFSelection) {
selection.color = UIColor.yellow
self.pdfview.currentSelection = selection
self.pdfview.go(to: selection)
calculateStandByMood()
}
Just add this protocol in pdfViewController :
SearchTableViewControllerDelegate
I think you can reach to the current selection using
pdfView.go(to selection: pdView.currentSelection)
According to this doc, PDF can be navigated using selection, destination and rect
https://developer.apple.com/documentation/pdfkit/pdfview/1505172-go