Swift UITableView willSelectRowAt doesn't work properly - ios

In my tableView I want the cells to be unselectable.
So I wrote in my TableViewController:
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if indexPath.section == 0 {
return nil
} else {
if switchIsOn! {
return indexPath
} else {
return nil
}
}
}
It works as expected when I make a normal touch in the cells, but when I hold my finger down on the cell, it becomes selected anyway. How can I avoid this?

When switch state changes call tableView.reloadData(), then add this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
if indexPath.section != 0 && !switchIsOn! {
cell.selectionStyle = .none
} else {
cell.selectionStyle = .default
}
return cell
}

Related

Selecting TableView Cell Activates Checkmark in Rows in Multiple Sections

I've implemented checkmarks (when row is selected) with the following code in cellForRowAt:
// Add a checkmark to row when selected
if selectedIngredients.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
However, when I select a row, that index.row from each section gets the checkmark:
This seems like it could be because I'm only specifying the indexPath.row, but not the section. How can I code this so that only the selected row within the section I selected gets the checkmark?
use data store for save checkmarks like this:
var selectedIngredients: Set<IndexPath> = [] // use set for unique save
then didSelect callBack:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
if self.selectedIngredients.contains(indexPath) {
self.selectedIngredients.remove(indexPath)
} else {
self.selectedIngredients.insert(indexPath)
}
self.tableView.reloadData()
}
after reload in CellForRow:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if selectedIngredients.contains(indexPath) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}
If you want it to have only one Row contain checkmark:
var selectedIngredients: IndexPath? = nil
and didSelect CallBack:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
self.selectedIngredients = indexPath
}
and finally:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if selectedIngredients == indexPath {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
}
you should add checkmarks in didSelect and remove them in didDeselect methods;
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
// update cell here
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// update cell here
}
also, have a look at this answer; https://stackoverflow.com/a/34962963/13754736

How to add different cell to tableview?

I have a tableview and I'm downloading data from firebase after that I reload tableview but I want to add more different cell to tableview too. For example my datas count is six and I want to add to second row and fifth row different cell. In the end I want to show eight cell.
I tried this code;
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 1 {
let cell = myTableView.dequeueReusableCell(withIdentifier: "makeLiveWallpaper") as! LiveWallTableViewCell
if indexPath.row == 1 {
cell.titleLabel.text = "Let's make LiveWallpaper"
}
return cell
}else{
if let cell = myTableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as? CategoryTableViewCell{
cell.category = category(at: indexPath)
cell.delegate = self
cell.setScrollPosition(x: offsets[indexPath] ?? 0)
return cell
}
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 1 {
return 140
}else{
return 255
}
}
But it is not adding new cell it is over write on cell
Once you got the data update your dataSource like given below:
data.insert("", at: 1)
data.insert("", at: 4)
self.tableView.reloadData()
update your Data Source Method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 1 {
// your custom Cell
return cell
} else if indexPath.row == 5 {
// you custom Cell
return cell
} else {
// normal cell
}
return UITableViewCell()
}
Hope it will hep you.

How to deselect selected cell in UITableView

Normally, when I touch UITableViewCell, then UITableViewCell is selected and highlighted.
But, again touch exactly same UITableViewCell, then nothing happen.
I want that if I touch selected UITableViewCell, then UITableVIewCell to deselect.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) else { return }
if cell.isSelected == true {
cell.isSelected = false
}
}
/////
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) else { return }
if cell.isSelected == false {
cell.isSelected = true
} else {
cell.isSelected = false
}
}
Both source code does not working. How do I fix this method?
Minimal working example (first 7 cells are selectable):
import UIKit
import PlaygroundSupport
class MyTableViewController: UITableViewController {
var selectedIndexPath: IndexPath? = nil
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 7
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndexPath == indexPath {
// it was already selected
selectedIndexPath = nil
tableView.deselectRow(at: indexPath, animated: false)
} else {
// wasn't yet selected, so let's remember it
selectedIndexPath = indexPath
}
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyTableViewController()

UITableView in Custom ViewController: Custom UITableViewCells Are Overlapping

I'm calling a TableView inside of a custom ViewController. In my UITableView, my cells overlap. Like so
In the storyboard editor, I have the Row Height set to Custom at 63pts, but they look like they're actually using the the default height that the cell would be if you unchecked the Custom box.
Like in some of the other solutions tried implementing the heightForRowAt function but it doesn't do anything. I've tried using obscenely large numbers, but the result is always exactly as it was before.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if(self.view.traitCollection.horizontalSizeClass == .compact ||
self.view.traitCollection.verticalSizeClass == .compact) {
cellHeight = 55
return 55
}
else{
return 63
}
}
The only thing in solutions I've seen so far that looks at all promising is this one. iOS UITableViewCell overlapping
I've tried implementing the prepareForReuse Function in my custom TableViewCell class file, but I didn't know what I was actually supposed to add to the function, so I just called the super function and added a print statement
--- Full TableView Code ---
extension SavingViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "WishlistTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? WishlistTableViewCell else {
fatalError("The dequeued cell is not an instance of WishlistTableViewCell.")
}
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if(self.view.traitCollection.horizontalSizeClass == .compact ||
self.view.traitCollection.verticalSizeClass == .compact) {
cellHeight = 55
return 55
}
else{
return 63
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
/*
let resultRemoving = bookmarks[indexPath.row]
if var bookmarkData = defaults.object(forKey:"bookmarkDict") as? [String: [String]] {
bookmarkData.removeValue(forKey: resultRemoving.resultURL)
defaults.set(bookmarkData, forKey:"bookmarkDict")
}
defaults.synchronize()
*/
items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
}
Currently heightForRowAt is not being called since heightForRowAt method is a UITableViewDelegate method so
Your extension should look like this:
Add UITableViewDelegate
extension SavingViewController: UITableViewDataSource, UITableViewDelegate {
}

How to use multiple UITableView in single view Controller in iOS - Swift

I am new to iOS development. Currently, I am working on a project in which I use more than two UITableViews in a single view controller, but both data sources come from server one by one. When the first api hit, it shows the result, but after select item from that list I am unable to show the response in list.
Here is my code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("sdfsdfsf")
var count:Int?
if tableView == self.pat_search_listview {
count = serach_data.count
}
else if tableView == self.visit_listview {
count = all_vist_data.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if tableView == self.pat_search_listview {
cell.textLabel?.text = serach_data[indexPath.row].name + " " + serach_data[indexPath.row].id
}
else if tableView == self.visit_listview {
print("second listview")
cell.textLabel?.text = all_vist_data[indexPath.row].date
}
return cell
}
check the Outlet connections for both tableViews... both shouldn't be nil in viewDidLoad
in viewDidLoad:
self.pat_search_listview.dataSource = self;
self.visit_listview = self;
self.pat_search_listview.tag = 0
self.visit_listview.tag = 1
in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 0
...
else
...
Make sure to set delegate and data source and don't forget to reload the table after adding/updating the arrays.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if tableView == self.pat_search_listview
{
return serach_data.count/*pat_search_listview's Array count*/
}
else if tableView == self.visit_listview
{
return all_vist_data.count/*visit_listview Array count*/
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if tableView == self.pat_search_listview
{
cell.textLabel?.text = serach_data[indexPath.row].name + " " + serach_data[indexPath.row].id
}
else if tableView == self.visit_listview
{
print("second listview")
cell.textLabel?.text = all_vist_data[indexPath.row].date
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if tableView == self.pat_search_listview
{
//--- Item at index from pat_search_listview
}
else if tableView == self.visit_listview
{
print("second listview")
//--- Item at index from visit_listview
}
}

Resources