Deleting a UITableView cell in a specific section - ios

There is a task. Each cell contains a button by clicking which you want to delete this cell. The problem is that sections are used to delineate the entire list by category. The data I take from Realm DB. removal must occur under two conditions because the name is repeated, so you need to consider the name from the label and the name of the section. I will be very grateful for the sample code with comments.
import UIKit
import RealmSwift
class PurchesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var purchesTableView: UITableView!
let manage = ManagerData()
override func viewDidLoad() {
super.viewDidLoad()
purchesTableView.delegate = self
purchesTableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
purchesTableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return manage.loadPurchases().0.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return manage.loadPurchases().0[section]
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return manage.loadPurchases().1[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "purchesCell", for: indexPath) as! CustomPurchesTableViewCell
cell.productLabel.text = manage.loadPurchases().1[indexPath.section][indexPath.row]
cell.weightProductLabel.text = manage.loadPurchases().2[indexPath.section][indexPath.row]
cell.weightNameLabel.text = manage.loadPurchases().3[indexPath.section][indexPath.row]
// cell.boughtButton.addTarget(self, action: #selector(removeProduct), for: .touchUpInside)
return cell
}
}
class CustomPurchesTableViewCell: UITableViewCell {
#IBOutlet weak var boughtButton: UIButton!
#IBOutlet weak var productLabel: UILabel!
#IBOutlet weak var weightProductLabel: UILabel!
#IBOutlet weak var weightNameLabel: UILabel!
#IBAction func removePurches(_ sender: Any) {
print("remove")
}
}
method for get data
func loadPurchases() -> ([String], Array<Array<String>>, Array<Array<String>>, Array<Array<String>>) {
var sections: [String] = []
var product = Array<Array<String>>()
var weight = Array<Array<String>>()
var nameWeight = Array<Array<String>>()
let realm = try! Realm()
let data = realm.objects(Purches.self)
for item in data {
if sections.contains(item.nameDish) == false {
sections.append(item.nameDish)
}
}
for a in sections {
var productArr = Array<String>()
var weightArr = Array<String>()
var nameWeightArr = Array<String>()
for prod in data {
if a == prod.nameDish {
productArr.append(prod.product)
weightArr.append(prod.weight)
nameWeightArr.append(prod.nameWeigh)
}
}
product.append(productArr)
weight.append(weightArr)
nameWeight.append(nameWeightArr)
}
return (sections, product, weight, nameWeight)
}

Index path you will get in cell class
Index path have two property section and row for table view
Now you can create on more method in Controller class and assign to a variable to every cell or you can use editAction provided by table view for delete

in order to get number section and row you need create IBOutlet in custom cell and on ViewController class is created addTarget for your button.
Example code at the bottom.
import UIKit
import RealmSwift
class PurchesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var purchesTableView: UITableView!
let manage = ManagerData()
//... more code ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "purchesCell", for: indexPath) as! CustomPurchesTableViewCell
cell.productLabel.text = manage.loadPurchases().1[indexPath.section][indexPath.row]
cell.weightProductLabel.text = manage.loadPurchases().2[indexPath.section][indexPath.row]
cell.weightNameLabel.text = manage.loadPurchases().3[indexPath.section][indexPath.row]
cell.boughtButton.addTarget(self, action: #selector(removePurches(_:)), for: .touchUpInside)
return cell
}
#objc func removePurches(_ sender: UIButton) {
let position: CGPoint = sender.convert(CGPoint.zero, to: purchesTableView)
let indexPath: IndexPath! = self.purchesTableView.indexPathForRow(at: position)
print("indexPath.row is = \(indexPath.row) && indexPath.section is = \(indexPath.section)")
purchesTableView.deleteRows(at: [indexPath], with: .fade)
}
}
and custom class CustomPurchesTableViewCell for cell
class CustomPurchesTableViewCell: UITableViewCell {
#IBOutlet weak var boughtButton: UIButton! // you button for press
#IBOutlet weak var productLabel: UILabel!
#IBOutlet weak var weightProductLabel: UILabel!
#IBOutlet weak var weightNameLabel: UILabel!
}

Related

tableview doesn't show anything?

I made sure that my cell identifier was correct I'm not too sure what the problem is. I've been rereading the code on this viewController and I'm not sure if I'm missing something or if there's a specific reason why my tableview isn't loading.
import UIKit
import JGProgressHUD
class BasketViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = footerView
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//MARK: TO DO CHECK IF USER IS LOGGED IN
loadBasketFromFirestore()
}
//MARK: VARS
var basket : basket?
var allItems : [Item] = []
var purchaseItemID : [String] = [] //holds id of items you want to purchase
var hud = JGProgressHUD(style: .dark)
//MARK: IBOUTLETS
#IBOutlet weak var totalPriceLabel: UILabel!
#IBOutlet weak var totalItemsInBasket: UILabel!
#IBOutlet weak var checkOutButton: UIButton!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var footerView: UIView!
//MARK: IBACTIONS
#IBAction func checkOutButtonTapped(_ sender: Any) {}
//something is wrong with
//MARK: DOWNLOAD BASKET
private func loadBasketFromFirestore(){
//MARK: CHANGE 1234 TO A USER ID STRING
downloadBasketFromFirestore("1234") { (basket) in
self.basket = basket
self.getBasketItems()
}
}
private func getBasketItems(){
if (basket != nil) {
print("getting items")
downloadItems(_withIDS: basket!.itemID) { (allItems) in
self.allItems = allItems
self.tableView.reloadData()
}
} else { print("basket is nil")}
}
}
extension BasketViewController : UITableViewDataSource , UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "basketCell", for: indexPath) as! ITEMTableViewCell
cell.generateCellForITEMS(item: allItems[indexPath.row])
return cell
}
}

passing data from button in cell to another tableview?

how do I pass data from button in menu tableview to cart tableview?
would I segue it, use closures, protocol/delegates, something else?
Im having trouble passing data from my AddtoCart Button in my MenuViewController to CartViewController
the objective is to put items in the CartVC when the ATC button is pressed in the MenuCell
The CartButton on the NavBar in the MenuVC segues to the CartVC when pressed
The ATC button in the cell passes all the selected cells data to the cartVC (image, name, category, weight & price)
Im using Cloud Firestore to post data to populate my VC cells
I have tried so many different solutions posted on stack and still nothing seems to works, I have been stuck on this for almost 2 weeks... any help would be much much appreciated
import UIKit
import SDWebImage
import Firebase
class MenuCell: UITableViewCell {
weak var items: Items!
#IBOutlet weak var name: UILabel!
#IBOutlet weak var category: UILabel!
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var weight: UILabel!
#IBOutlet weak var price: UILabel!
#IBOutlet weak var addToCart: RoundButton!
func configure(withItems items: Items) {
name.text = items.name
category.text = items.category
image.sd_setImage(with: URL(string: items.image))
price.text = items.price
weight.text = items.weight
self.items = items
}
}
import UIKit
import Firebase
import FirebaseFirestore
class MenuViewController: UITableViewController {
#IBOutlet weak var cartButton: BarButtonItem!!
#IBOutlet weak var tableView: UITableView!
var itemSetup: [Items] = []
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MenuCell") as? MenuCell else { return UITableViewCell() }
cell.configure(withItem: itemSetup[indexPath.row])
return cell
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Cart.currentCart.cartItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = Cart.currentCart.CartItems[indexPath.row]
cell.lblWeight.text = cart.items.weight
cell.lblMealName.text = "\(cart.items.category): \(cart.items.name)"
cell.lblSubTotal.text = "$\(cart.items.price)"
cell.imageUrl // can't figure out how to pass image
return cell
}
}
class CartItem {
var items: Items
init(items: Items) {
self.items = items
}
}
The first thing I would do is get rid of CartItem - It doesn't seem to be doing anything except wrapping an Items instance, and you have some confusion in your code as to whether you are using CartItem or Items (I would probably also rename Items to Item - singular).
class Cart {
static let currentCart = Cart()
var cartItems = [Items]()
}
To get the "add to cart" action from your cell you can use a delegation pattern or provide a closure to handle the action. I will use a closure
class MenuCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var category: UILabel!
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var weight: UILabel!
#IBOutlet weak var price: UILabel!
#IBOutlet weak var addToCart: RoundButton!
var addActionHandler: (() -> Void)?
func configure(withItems items: Items) {
name.text = items.name
category.text = items.category
image.sd_setImage(with: URL(string: items.image))
price.text = items.price
weight.text = items.weight
}
#IBAction func addTapped(_ sender: UIButton) {
self.addActionHandler?()
}
}
Now, in your menu cellForRowAt you can provide the action handler:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MenuCell") as! MenuCell // Just crash at this point if there isn't a valid cell identifier configured
let item = itemSetup[indexPath.row]
cell.configure(withItem: item)
cell.addActionHandler = {
Cart.currentCart.items.append(item)
}
return cell
}
And that should be all you need to do - When you segue to the cart view controller, it will show the current contents of the cart.
Note that you could improve your cart data model somewhat by allowing it to have a quantity for each item and providing an add(item:) function that incremented the quantity if the item was in the cart

How to pass data on button clicked in cell to another tableview?

First: How would I be able to pass data from the ItemVC Cell to the CartVC on button Clicked (Add To Cart Button(ATC)) in the selected cell, since I am no trying to use didSelectRowAt to pass the data to the CartVC. but the ATC btn to pass the cells data to the CartVC
my Segue from the ItemVC to the CartVC is in the BarButtonItem(cartBtn) so I dont want to jump to the CartVc when pressing the ATC button but only pass selected items data to CartVC when the ATC is pressed
Second how would I be able to pass the increment/decrement value in lblQty to to the CartVC when the ATC is pressed as well to be able to present a more accurate Subtotal
import UIKit
import SDWebImage
import Firebase
class ItemCell: UITableViewCell {
weak var items: Items!
#IBOutlet weak var name: UILabel!
#IBOutlet weak var category: UILabel!
#IBOutlet weak var productImage: UIImageView!
#IBOutlet weak var weight: UILabel!
#IBOutlet weak var price: UILabel!
#IBOutlet weak var lblQty: UILabel!
#IBOutlet weak var addToCart: RoundButton!
#IBOutlet weak var plusBtn: RoundButton!
#IBOutlet weak var minusBtn: RoundButton!
func configure(withItems : Items) {
name.text = product.name
category.text = items.category
image.sd_setImage(with: URL(string: items.image))
price.text = items.price
weight.text = items.weight
}
}
import UIKit
import Firebase
import FirebaseFirestore
class ItemViewController: UITableViewController {
#IBOutlet weak var cartBtn: BarButtonItem!!
#IBOutlet weak var tableView: UITableView!
var itemSetup: [Items] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
fetchItems { (items) in
self.itemSetup = items.sorted
self.tableView.reloadData()
}
}
func fetchItems(_ completion: #escaping ([Items]) -> Void) {
// -** FireStore Code **-
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as? CartViewController {
vc.items = self.itemSetup
}
}
#objc func plusItem(_ sender: UIButton) {
// -** increase Qty Code **-
}
//Function to decrement item count
#objc func minusItem(_ sender: UIButton) {
// -** decrease Qty Code **-
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell") as? ItemCell else { return UITableViewCell() }
cell.configure(withItem: itemSetup[indexPath.row])
cell.lblQty.text = "\(self.imageSetup[indexPath.row].count)"
cell.plusBtn.tag = indexPath.row
cell.plusBtn.addTarget(self, action: #selector(self.plusItem(_:)), for: .touchUpInside)
cell.minusBtn.tag = indexPath.row
cell.minusBtn.addTarget(self, action: #selector(self.minusItem(_:)), for: .touchUpInside)
return cell
}
}
class CartViewController: UIViewController {
var items: Items!
#IBOutlet weak var cartTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
cartTableView.dataSource = self
cartTableView.delegate = self
}
}
extension CartViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Cart.currentCart.cartItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = Cart.currentCart.CartItems[indexPath.row]
cell.qty.text = "\(cart.qty)"
cell.lblMealName.text = "\(cart.items.category): \(cart.items.name)"
cell.lblSubTotal.text = "$\(cart.items.price1 * Float(cart.qty))"
cell.imageUrl // can't figure out how to pass image
return cell
}
}
import Foundation
class CartItem {
var items: Items
var qty: Int
init(items: Items, qty: Int) {
self.items = items
self.qty = qty
}
}
class Cart {
static let currentCart = Cart()
var cartItems = [CartItem]()
}
Just create a protocol to create a delegate and assign it to your cart class when the cell is initialized
protocol ItemCellDelegate {
func itemCell(didTapButton button: UIButton)
}
Then have a delegate property in the ItemCell
class ItemCell {
weak var delegate: ItemCellDelegate?
...
// Then call the delegate method when the buttons is tapped.
func buttonTapped() {
delegate?.itemCell(didTapButton: theCellsButton)
}
}
Then make your Cart conform to the delegate
extension Cart: ItemCellDelegate {
func itemCell(didTapButton button: UIButton) {
// Do you stuff with button, or any other data you want to pass in
}
}
Then set the delegate before the cell is returned.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell
let cart = Cart.currentCart.CartItems[indexPath.row]
cell.qty.text = "\(cart.qty)"
cell.lblMealName.text = "\(cart.items.category): \(cart.items.name)"
cell.lblSubTotal.text = "$\(cart.items.price1 * Float(cart.qty))"
cell.delegate = Cart.currentCart //You should rename this static var to just 'current'
return cell
}

Swift 5 Collapsible table header

I have to do this implementation, I need a list of cells representing month periods, where each one is collapsed, and when clicked it shows its content, I used two cells prototypes based on some tutorials I found but I'm really new into swift programming, I can't get the expected result, I share some screens and actual code. Hope someone could help me.
class BillingListCell: UITableViewCell{
#IBOutlet weak var billWrapper: UIView!
#IBOutlet weak var billTotal: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
class BillingListHeaderCell: UITableViewCell{
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var numberLabel: UILabel!
#IBOutlet weak var statusButton: UIButton!
func setExpanded() {
statusButton.setImage(UIImage(systemName: "chevron.up"), for: .normal)
}
func setCollapsed() {
statusButton.setImage(UIImage(systemName: "chevron.down"), for: .normal)
}
}
class BillingListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var billingListTableView: UITableView!
var paymentArray: [String] = ["data","data2", "data3"]
private let numberOfActualRowsForSection = 1
func numberOfSections(in tableView: UITableView) -> Int {
return paymentArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// First will always be header
return false ? (1+numberOfActualRowsForSection) : 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.row == 0){
let cell = tableView.dequeueReusableCell(withIdentifier: "BillingListHeaderCell", for: indexPath) as! BillingListHeaderCell
cell.setCollapsed()
return cell
}else{
let cell = tableView.dequeueReusableCell(withIdentifier: "BillingListCell", for: indexPath) as! BillingListCell
cell.billWrapper.layer.cornerRadius = 15
cell.billWrapper.layer.borderWidth = 1
cell.billWrapper.layer.borderColor = UIColor.blue.cgColor
cell.billTotal.text = "1234"
return cell
}
}

Swift -> my prototype cell (UITableViewCell) doesn't show in my UIViewController with a UITableView

My storyboard looks like this
and my code is the following
UIViewController
class DownLoadSoundsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: View Controller Properties
let viewName = "DownLoadSoundsViewController"
#IBOutlet weak var visualEffectView: UIVisualEffectView!
#IBOutlet weak var dismissButton: UIButton!
#IBOutlet weak var downloadTableView: UITableView!
// MARK: Properties
var soundPacks = [SoundPack?]() // structure for downloadable sounds
override func viewDidLoad() {
super.viewDidLoad()
downloadTableView.dataSource = self
downloadTableView.delegate = self
downloadTableView.register(DownLoadTableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfSoundPacks
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let method = "tableView.cellForRowAt"
//if (indexPath as NSIndexPath).section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "downloadTableViewCell", for: indexPath) as! DownLoadTableViewCell
cell.backgroundColor = UIColor.green
if soundPacks[(indexPath as NSIndexPath).row]?.price == 0 {
cell.soundPackPriceUILabel.text = "FREE"
} else {
cell.soundPackPriceUILabel.text = String(format: "%.2", (soundPacks[(indexPath as NSIndexPath).row]?.price)!)
}
//cell.textLabel?.text = soundPacks[(indexPath as NSIndexPath).row]?.soundPackTitle
cell.soundPackTitleUILabel.text = soundPacks[(indexPath as NSIndexPath).row]?.soundPackTitle
cell.soundPackAuthorUILabel.text = soundPacks[(indexPath as NSIndexPath).row]?.author
cell.soundPackShortDescription.text = soundPacks[(indexPath as NSIndexPath).row]?.shortDescription
cell.soundPackImage.image = UIImage(named: "Placeholder Icon")
DDLogDebug("\(viewName).\(method): table section \((indexPath as NSIndexPath).section) row \((indexPath as NSIndexPath).row))")
return cell
//}
}
UItableViewCell
class DownLoadTableViewCell: UITableViewCell {
#IBOutlet weak var soundPackImage: UIImageView!
#IBOutlet weak var soundPackTitleUILabel: UILabel!
#IBOutlet weak var soundPackAuthorUILabel: UILabel!
#IBOutlet weak var soundPackShortDescription: UILabel!
#IBOutlet weak var soundPackPriceUILabel: UILabel!
let gradientLayer = CAGradientLayer()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
But I get the following;
I am sure I am doing something small incorrectly, but as of yet can't figure it out. Looked through many examples included my own code where I have gotten this working before.
Not a single one of my settings for the tableview are getting invoked except the number of cells. But everything in;
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{...}
is not working.
Help is appreciated.
I think you need to reload the tableView after getting data from Firebase
self.saveMixesTableView.reloadData()

Resources