How do I delete UITableview cells by tapping a UIButton? - ios

I want to delete all the UITableviewCells in my Tableview by tapping a button
UITableView DataSource Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return UserList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FriendAddCell" , for: indexPath) as! AddFriendLTableViewCell
cell.lb_Email.text = UserList[indexPath.row].userEmail
let imageUrl = URL(string: UserList[indexPath.row].imageUrl)
cell.img_Avatar.loadImageUrl(url: imageUrl!)
return cell
}
My Button Function
#IBAction func btn_NewAddUser(_ sender: Any) {
UserList.removeAll()
table_SearchFirends.reloadData()
}
the cells I tried to delete still exist when I add a new cell
How can I delete all the cells by pressing the button?
How can I make the tableView as if there were no rows created?

How I can understand your problem that you see empty lines with separator lines on bottom.
Make this for remove extra lines:
tableView.tableFooterView = UIView()
And some advise - use camelCase style in Swift.

Related

Selection of UITableViewCell Changes when Scroll down in Swift

I am using a UITableView and what I am doing is I am changing the color of the cell when I tap on the cell using didSelectRow function of UITableView at cellForRowAt. The thing which is bothering me is when I scroll down or scroll up, those cells whom I changed the color before were changed to other cells. Here is my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.backView.backgroundColor = .white
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = myTableView.cellForRow(at: indexPath) as! TasksTableViewCell
cell.backView.backgroundColor = UIColor(named: "primaryViewColor")
}
Does anyone knows why this happens? Does anyone has a solution that when only those cells changes color whom I tap on, and when I scroll down or move up only those cells have the other color?
cellForRowAt will be called every time that cell is displayed.
you need selected list to save selected index.
var listSelected: [Int] = []
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.backView.backgroundColor = listSelected.contains(indexPath.row) ? UIColor(named: "primaryViewColor") : .white
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if listSelected.contains(indexPath.row) {
listSelected = listSelected.filter{$0 != indexPath.row}
} else {
listSelected.append(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}
I encountered do you see the problem many times. Even if using and iVar can solve the problem, You are mixing "Controller" logic and "Model" logic.
I usually prefer to move "selection" state inside the model.
Suppose You have a class "Contact" you use to fill cell data (usual MVC pattern)
I add:
class contact{
..
var selected = false
}
AND in TV delegation method I use to apply selection, OR better I use a custom selection method in a custom cell (for example to see a √ element in cell)
As a bonus multiple selection come for free, and you can also save current selections for next run :)
So as I understand you select a cell and after that other cells look like they are selected?
If so I think this is happening because you change the background color of the cell and tableViews and collectionViews are reusing the cells, basically keeping the background you changed behind.
TableViewCells are reused as soon as they leave the visible area.
This means that a cell whose background you have colored will be deleted from the view hierarchy as soon as it is scrolled up or down. If the corresponding row is scrolled in again, the function cellForRowAt is called again for this IndexPath and the cell gets a white background.
The easiest is to save the IndexPaths of the selected cells and check in the cellForRowAt function if the current cell has to be selected.
Add the following var to the viewController class:
var selectedIndexPaths = Set<IndexPath>()
and modify the tableView delegate methods:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = myTableView.dequeueReusableCell(withIdentifier: "TasksTableViewCell") as! TasksTableViewCell
cell.backView.backgroundColor = (selectedIndexPaths.contains(indexPath) ? UIColor(named: "primaryViewColor") : .white)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if selectedIndexPaths.contains(indexPath)
{
selectedIndexPaths.remove(indexPath)
}
else
{
selectedIndexPaths.insert(indexPath)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
You can use
step 1: create model
class DemoModel {
var isSelected: Bool = false
var color: UIColor = .While
}
step 2: and in tableview
var listDemo: [DemoModel] = [DemoModel(),...]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myTableView.dequeueReusableCell(withIdentifier:
"TasksTableViewCell") as! TasksTableViewCell
var obj = listDemo[indexPath.row]
cell.backView.backgroundColor = obj.color
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var obj = listDemo[indexPath.row]
obj.color = UIColor(named: "primaryViewColor")
tableView.reloadRows(at: [indexPath], with: .automatic)
}

When deleting row using trailingSwipeActionsConfigurationForRowAt strange missing other rows issue

I am trying to delete row from UITableView by using trailingSwipeActionsConfigurationForRowAt function.
The row gets deleted and disappears. This part is ok.
But next rows that are coming to the screen or when I swipe down the same amount as the rows been deleted are not even loaded on the tableView.
![img1]https://poirot.deus4.com/photo_2019-06-12_16-44-01.jpg
![img2]https://poirot.deus4.com/photo_2019-06-12_16-43-56.jpg
![img3]https://poirot.deus4.com/photo_2019-06-12_16-43-49.jpg
![img4]https://poirot.deus4.com/photo_2019-06-12_16-43-38.jpg
[video]https://poirot.deus4.com/RPReplay_Final1560345600.mp4
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredProducts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: .cellID, for: indexPath) as! ProductTableCell
cell.backgroundColor = .red
return cell
}
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let hide = UIContextualAction(style: .destructive, title: "Hide") { action, view, completion in
self.filteredProducts.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
completion(true)
}
hide.image = #imageLiteral(resourceName: "hdie_product")
hide.backgroundColor = .midGrey
let conf = UISwipeActionsConfiguration(actions: [hide])
return conf
}
The code you showed obviously works, thus the problem is elsewhere.
Without other code I suspect that the problem is because table view cells are re-used: When you scroll your table view, some cells are scrolled out of view and can be reused. Cells that are scrolled in are either re-used cells or new cells.
In any case, the table view datasource function tableView(_:cellForRowAt:) must be used to configure the displayed cells.
It seems too me that you do not configure the cells in tableView(_:cellForRowAt:).
If so, re-used cells look as the were when they have been scrolled out, but new cells are simply blank.
So I suggest to check if you really configure all the cells in tableView(_:cellForRowAt:) correctly.
The issue was that I did not call super.prepareForReuse() inside TablewViewCell
override func prepareForReuse() {
super.prepareForReuse() // this was missing
}

As UITableviewCell count more than 10 and if I click on top of button it automatically click in last of UITableViewCell button. any idea?

In my UITableViewCell have button AddToCart buttons. As if my UITableView data is more than 10 means I have to scroll to see all data. So now if I will on first button of first UITableViewCell as I scroll down to see all records of tableview than automatically last or second last button will also click I am unable to find the problem why this is happening
I am implementing first time this type of functionality so got stuck to resolve the problem
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 13
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tblCell") as! ProductTableViewCell
cell.btnAddToCart.tag = indexPath.row
cell.btnAddToCart.addTarget(self, action: #selector(addToCartDell(sender:)), for: .touchUpInside)
return cell
}
This function is used for hide and show Add To Cart button option.
#objc func addToCartDell(sender: UIButton) {
let tagVal = sender.tag
let indexPath = IndexPath(item: tagVal, section: 0)
if let cell = tblProduct.cellForRow(at: indexPath) as? ProductTableViewCell {
cell.btnAddToCart.isHidden = true
}
}
Cells are reused. You don't save the hidden state of the cell so when a cell is reused the latest state is preserved.
In Swift the most efficient and reliable solution is to save the state added to cart in the data model and use a callback closure to update the UI in cellForRow.
In the data model add a property addedToCart, it's assumed that a custom struct or class is used as data model
var addedToCart = false
In ProductTableViewCell add the callback variable and an IBAction. Connect the IBAction to the button
var callback : (()->())?
#IBAction func buttonPressed(_ sender : UIButton) {
callback?()
}
In the controller in cellForRow handle the callback, products represents the data source array
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tblCell") as! ProductTableViewCell
let product = products[indexPath.row]
cell.btnAddToCart.isHidden = product.addedToCart
cell.callback = {
product.addedToCart = true
cell.btnAddToCart.isHidden = true
}
return cell
}
No tags, no target/action, no protocols, no extra work in willDisplayCell .
This issue is turning up because we re-user same cell for displaying any further rows that was not visible yet.
you may implement this method to correct the display of any further cells
optional func tableView(_ tableView: UITableView,
willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath)
Customize the cell as you want it to appear in this delegate method. This delegate method is called just before the cell is displayed, so you can do any customization here and it will turn up in the UI as per your customization.
If we go deep in to implementation.
There must be a model that keeps the state addedToCart in this model on basis of the button tapped in a particular row and use this same model's addedToCart (model.addedToCart) to show hide the button in delegate method.

Load 10 items at a time when scroll to bottom load more items on tableview ios ,swift , Firebase

Loading all the date from the firebase to the tableview at a time but i wanted to load 10 items at a time when i scroll to bottom again 10 items should load to the tableview, below is my code
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = items[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "inciCell") as!
IncidentCell
cell.delegate = self
cell.setupCell(with: item, indexPath)
return cell
}
}
In the delegate method cellForRowAtIndexPath you may check something like indexPath.row == items.count - 1.
if it's true, then you get 10 items from your DB and append it to your `items.
then do tableView.reloadData() to update the table view with 10 new items.
You may also make some nice spinner in the bottom (tableFooterView) of the table view. But it could be the next step.
Hope it helps.

UITableViewCells invisible

Requirement :
I have a list of UITableviewCell loaded from a nib that I'm presenting on UITableview. The first time I open the UIViewController all cells are shown correctly and work as expected.
Issue :
If I navigate back to the parent and then open the UIViewController again the UITableviewCell are 'invisible'. I say invisible because with a breakpoint in cellForRowAt I can see that the table view does load all cells and the cells are valid.
Code :
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 13
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (project?.sliderData.sliders[indexPath.row].view)! as UITableViewCell
print(cell.contentView.subviews.count)
if let left = cell.viewWithTag(2) as? UILabel {
left.text = "left"
}
if let middle = cell.viewWithTag(3) as? UILabel {
middle.text = "middle"
}
if let right = cell.viewWithTag(4) as? UILabel {
right.text = "right"
}
return cell
}
Screen Shot Image
Expected observation :
I was thinking that maybe the subviews of the cells get released because I don't have any bindings to them in IB. To test this I'm printing the count of subviews and writing some text to the subview labels. And everything seems to go fine, the cells are loaded and the labels are there but the cells just don't show up.
But then, if I scroll the TableView up and down a little to get some cells updated those cells do appear at the top and bottom of the view as shown in the pic.
You need to call dequeueReusableCell(withIdentifier: "cell") inside your code then will show your table cell. It will reuse cell for your all numbers of row data content.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UITableViewCell
return cell
}
More Details : How to create uitableview with multiple sections in iOS Swift.
Did not find reason why the tableView behaves the way it does so I solved the issue by dequeueing default cells. The views provided by the slider objects are added as subviews to the dequeued cells. Now the subviews can of course be any UIViews.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "sliderCell")
if cell == nil {
cell = UITableViewCell.init(style: .default, reuseIdentifier: "sliderCell")
}
cell?.addSubview((project?.sliderData.sliders[indexPath.row].view)!)
return cell!
}

Resources