Cell touch action is not responding on short touches in TableView - ios

I have a Scene in storyboard that contains HistoryTable with historyCell and own UserHistoryViewCell view. This cell and also table is set to User interaction Enabled in Traits and Interaction sections. Scrolling is disabled and Delay Touch Down is also disabled. This cell is not responding at didSelectRowAt func at short click (only when pressing longer than 5? secs). I have a Tap Gesture Recognizer in my Scene and also another table with same problem. I tried to disable Tap Gesture Recognizer, but it seems that it doesn't do anything special. I'm not sure where is problem, I have my tables delegated and using the code bellow. I also provide screenshots of Attributes inspector for the table and cell. Btw. My second table has sections, so its little bit messy.
Second Btw. I have delay touch down enabled at the screenshot, because it has no effect at all. Third Btw. I have historyButton in my historyTable which is for removing old records. It has no impact at the cell itself (I think) because same stuff happens to my second table without this button. Also it worked before I added sections to my second table.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var counter = 0
if tableView.tag == 1 {
counter = (UserDefaults.standard.stringArray(forKey: "HistoryArray") ?? [String]()).count
let base = 60
self.historyTableHeightConstraint.constant = CGFloat(base) + CGFloat(counter) * 40
} else {
switch section {
case 0:
counter = presenter.storelist?.count ?? 0
case 1:
counter = presenter.storelist?.count ?? 0
default:
counter = 0
notFoundLabel.isHidden = false
}
}
return counter
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 1 {
let defaults = UserDefaults.standard
let userSearchHistory = defaults.stringArray(forKey: "HistoryArray") ?? [String]()
let cell = tableView.dequeueReusableCell(withIdentifier: "historyCell", for: indexPath) as! UserHistoryTableViewCell
cell.titleLabel.text = userSearchHistory.reversed()[indexPath.row]
cell.historyButton.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
cell.historyButton.tag = indexPath.row
if self.editable == true {
let newImage = UIImage(named: "RemoveIcon")
cell.historyButton.setImage(newImage, for: .normal)
cell.historyButton.isEnabled = true
} else {
let newImage = UIImage(named: "searchHistoryIcon")
cell.historyButton.setImage(newImage, for: .normal)
cell.historyButton.isEnabled = false
}
return cell
} else {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "shopSearchCell", for: indexPath) as! ShopSearchTableViewCell
cell.shopLabel.text = presenter.storelist?[indexPath.row].storename
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchResultCell", for: indexPath) as! SearchResultCell
cell.SearchResultLabel.text = presenter.storelist?[indexPath.row].storename
return cell
default:
return UITableViewCell()
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(#function + "\(indexPath.row)")
}
func tableView(_ tableView: UITableView, titleForHeaderInSection
section: Int) -> String? {
if tableView.tag == 2 {
if section == 0 {
if self.tableView(tableView, numberOfRowsInSection: section) > 0 {
return "Search shop"
} else {
return nil
}
} else {
if self.tableView(tableView, numberOfRowsInSection: section) > 0 {
return "Search"
} else {
return nil
}
}
} else {
return nil
}
}
// Sectionæ•°
func numberOfSections(in tableView: UITableView) -> Int {
if tableView.tag == 2 {
return 2
}
return 1
}

Related

Single and MultiSelection cells in same tableView | Swift

Before duplicating this question, please be known that I've spent days on this issue, working hours, and looking for all same sort of questions on SO, but there is something I am missing or doing wrong.
I have a tableView in which the data is being populated via API response. Below is the model I have.
struct Model : Codable {
let bugClassification : [Bug]?
}
struct Bug : Codable {
let selectable : String? //Telling wether cell is single/Multi selected
var options : [Options]?
}
struct Options : Codable, Equatable {
let title : String?
let id: Int
var isCellSelected: Bool = false
}
Scenario
I want to create multiple sections, each having different cell depending upon the type of selectable, either single or multi. I have achieved that, but the problem I am getting is that whenever I scroll, random cells are also selected. Now, I know this behaviour is because of tableView reusing the cells. But I am confused as how to handle all this. Also, I want to put the validation on the sections, that is, every section should have atleast one cell selected. Kindly guide me in the right direction, and any small help would be appreciated. Below is my code.
CellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if bugClassification[indexPath.section].selectable?.lowercased() == "multi-select" {
//Multi-Selection
let cell = tableView.dequeueReusableCell(withIdentifier: multiSelectionCellID) as! MultiSelectionCell
let item = bugClassification[indexPath.section].options![indexPath.row]
cell.label.text = item.title
if item.isCellSelected {
cell.checkMarkImageView.alpha = 1
cell.checkMarkView.layer.borderColor = UIColor.white.cgColor
cell.checkMarkView.backgroundColor = .emerald
} else if item.isCellSelected {
cell.checkMarkImageView.alpha = 0
cell.checkMarkView.layer.borderColor = UIColor.veryLightBlue.cgColor
cell.checkMarkView.backgroundColor = .white
}
return cell
} else {
//Single-Selection
let cell = tableView.dequeueReusableCell(withIdentifier: singleSelectionCellID) as! SingleSelectionCell
let item = bugClassification[indexPath.section].options![indexPath.row]
cell.label.text = item.title
if item.isCellSelected {
cell.checkMarkImageView.alpha = 1
cell.checkMarkView.layer.borderColor = UIColor.emerald.cgColor
} else {
cell.checkMarkImageView.alpha = 0
cell.checkMarkView.layer.borderColor = UIColor.veryLightBlue.cgColor
}
return cell
}
}
DidSelectRow Method
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if bugClassification[indexPath.section].selectable?.lowercased() == "multi-select" {
var item = bugClassification[indexPath.section].options![indexPath.row]
item.isCellSelected = !item.isCellSelected
bugClassification[indexPath.section].options![indexPath.row] = item
self.tableView.reloadRows(at: [indexPath], with: .automatic)
} else {
let items = bugClassification[indexPath.section].options
if let selectedItemIndex = items!.indices.first(where: { items![$0].isCellSelected }) {
bugClassification[indexPath.section].options![selectedItemIndex].isCellSelected = false
if selectedItemIndex != indexPath.row {
bugClassification[indexPath.section].options![indexPath.row].isCellSelected = true
}
} else {
bugClassification[indexPath.section].options![indexPath.row].isCellSelected = true
}
self.tableView.reloadSections([indexPath.section], with: .automatic)
}
}
In cellForRowAt
if item.isCellSelected == true{
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
and update the model by every selection
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let item = bugClassification[indexPath.section].options![indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
if indexPath.section == 0{
item.isCellSelected.isSelected = false
}else{
item.isCellSelected.isSelected = false
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = bugClassification[indexPath.section].options![indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
if indexPath.section == 0{
item.isCellSelected.isSelected = true
}else{
item.isCellSelected.isSelected = true
}
}
}

How to remove row in UITableViewController presented as popover

I have a custom UITableViewController that I present as a popover in my app. In some of the cells there is a delete button (trash can) to remove that item. Everything works as it should except that I the UI is not update when pressing the delete button. That is, the data is cleared and I call self.tableView.reloadData(), but the cell remains visible in the UI. (Pressing the delete button again makes the app crash in my C++ code because of an assert). I have no storyboard or xib as I do not need it. I only want this to be in code.
What am I missing? It might be something simple, but I cannot fathom why. I have tried:
Separate data source implementation.
Calling reloadData() both sync and async.
Setting delegate to self.
Various other hacks.
Here is the UITableViewController implementation:
import Foundation
class IngredientInfoPopoverViewController : UITableViewController
{
var slViewController: ShoppingListViewController?;
var ingredientName: String = "Ingrediens";
#IBOutlet var uniqueIngredients: [Ingredient] = []; // Unique per *recipe* so that we can list all the recipes for the ingredients
var clickedCellIndexPath: IndexPath? = nil;
enum SECTIONS : Int
{
case HEADER = 0;
case RECIPE = 1;
}
static let ROW_HEIGHT = 44;
override func viewDidLoad()
{
super.viewDidLoad();
tableView.register(UINib(nibName: "OpenIngredientInfoCell", bundle: nil), forCellReuseIdentifier: "OpenIngredientInfoCell");
tableView.register(UINib(nibName: "OpenRecipeCell", bundle: nil), forCellReuseIdentifier: "OpenRecipeCell");
tableView.separatorStyle = .singleLine;
tableView.bounces = false; // "Static" table view
updateSize();
}
func updateSize()
{
let totalCount = min(uniqueIngredients.count + 1, 6); // + 1: header row. min: Allow max 5 recipes in list (enables scrolling)
self.preferredContentSize = CGSize(width: 300, height: totalCount * IngredientInfoPopoverViewController.ROW_HEIGHT);
}
func setup(slvc: ShoppingListViewController?, ingredients: [Ingredient], clickedCellIndexPath: IndexPath)
{
self.slViewController = slvc;
self.clickedCellIndexPath = clickedCellIndexPath;
if (ingredients.count > 0)
{
let first = ingredients[0];
for i in ingredients
{
assert(i.getId() == first.getId());
}
ingredientName = first.getName();
var uniqueRecipeNames: Set<String> = [];
for i in ingredients
{
uniqueRecipeNames.insert(i.getRecipeName());
}
let sorted = uniqueRecipeNames.sorted();
uniqueIngredients.removeAll();
for s in sorted
{
for i in ingredients
{
if (i.getRecipeName() == s)
{
uniqueIngredients.append(i);
break;
}
}
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int
{
return 2;
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
switch section
{
case SECTIONS.HEADER.rawValue:
return 1;
case SECTIONS.RECIPE.rawValue:
return uniqueIngredients.count;
default:
assert(false);
return 0;
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
switch (indexPath.section)
{
case SECTIONS.HEADER.rawValue:
assert(indexPath.row == 0);
if (uniqueIngredients.count > 0)
{
let ingredient = uniqueIngredients[0]; // All are the same ingredient
self.dismiss(animated: true, completion: nil);
slViewController?.onIngredientInfoButtonClicked(ingredient);
}
break;
case SECTIONS.RECIPE.rawValue:
if (indexPath.row < uniqueIngredients.count)
{
let ingredient = uniqueIngredients[indexPath.row];
self.dismiss(animated: true, completion: nil);
slViewController?.onRecipeInfoButtonClicked(ingredient);
}
break;
default:
break;
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = UITableViewCell();
switch (indexPath.section)
{
case SECTIONS.HEADER.rawValue:
if (uniqueIngredients.count > 0)
{
let ingredient = uniqueIngredients[0];
let cell = tableView.dequeueReusableCell(withIdentifier: "OpenIngredientInfoCell", for: indexPath) as! OpenIngredientInfoCell;
cell.setup(ingredient);
}
break;
case SECTIONS.RECIPE.rawValue:
if (indexPath.row < uniqueIngredients.count)
{
cell.selectionStyle = .none; // Without this the cell contents become gray and disappear when long pressing! FML
let ingredient = uniqueIngredients[indexPath.row];
let cell = tableView.dequeueReusableCell(withIdentifier: "OpenRecipeCell", for: indexPath) as! OpenRecipeCell;
cell.setup(self, ingredient, clickedCellIndexPath);
}
break;
default:
break;
}
return cell;
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return CGFloat(IngredientInfoPopoverViewController.ROW_HEIGHT);
}
func ingredientRemoved(_ ingredient: Ingredient)
{
for i in 0..<uniqueIngredients.count
{
if (uniqueIngredients[i].getRecipeId() == ingredient.getRecipeId())
{
uniqueIngredients.remove(at: i);
// let indexPath = IndexPath(row: i, section: SECTIONS.RECIPE.rawValue);
// self.tableView.deleteRows(at: [indexPath], with: .fade);
DispatchQueue.main.async {
self.tableView.reloadData();
}
break;
}
}
if (uniqueIngredients.count == 0)
{
self.dismiss(animated: true, completion: nil);
}
else
{
DispatchQueue.main.async {
self.tableView.reloadData();
}
}
}
}
Here is how I present the IngredientInfoPopoverViewController:
#objc func ingredientInfoClicked(_ sender: UITapGestureRecognizer)
{
let tapLocation = sender.location(in: self.tableView)
let indexPath = self.tableView.indexPathForRow(at: tapLocation)!
let ingredients = CppInterface.shoppingList.getIngredients(UInt(indexPath.section), position: UInt(indexPath.row));
let controller = IngredientInfoPopoverViewController();
controller.setup(slvc: self, ingredients: ingredients!, clickedCellIndexPath: indexPath);
controller.modalPresentationStyle = .popover;
controller.popoverPresentationController!.delegate = self;
self.present(controller, animated: true, completion: {
self.tableView.reloadData();
});
}
Here is how the view controller looks when presented. If I click the trash can on one of the items, the data is cleared, but the cell is not removed from the UI, which is what I am trying to achieve.
I'm actually surprised your tableView shows any data at all. Because you declare cell as a let in cellForRowAt when you do let cell = UITableViewCell();, that makes it immutable, and the first cell (outside of the switch) is the one that should technically get returned. Hence why no data should be displaying. And probably also the reason why your tableView is not updating correctly.
Anyway, you should only declare cell when you're dequeueing it, and you should as much as possible, avoid force-unwrapping of a variable.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == SECTIONS.HEADER.rawValue, let cell = tableView.dequeueReusableCell(withIdentifier: "OpenIngredientInfoCell", for: indexPath) as? OpenIngredientInfoCell {
// not sure this check is necessary, but I'm adding it because it was in your original code
guard uniqueIngredients.count > 0 else { return UITableViewCell() }
let ingredient = uniqueIngredients[0]
cell.setup(ingredient)
return cell
} else if indexPath.section == SECTIONS.RECIPE.rawValue, let cell = tableView.dequeueReusableCell(withIdentifier: "OpenRecipeCell", for: indexPath) as? OpenRecipeCell {
// it shouldn't be possible for the indexPath to ever be greater than the dataSource items count, but I'll keep the check
guard indexPath.row < uniqueIngredients.count else { return UITableViewCell() }
cell.selectionStyle = .none
let ingredient = uniqueIngredients[indexPath.row]
cell.setup(self, ingredient, clickedCellIndexPath)
return cell
}
return UITableViewCell()
}
I've removed the semi-colons as they're not necessary in Swift.
For specifying the table cells' reuse identifiers, using the class names would probably be better. So you would use "\(OpenRecipeCell.self)" instead of "OpenRecipeCell"
If you are using the defaulted way of editing a UITableView (either swiping or entering edit mode), then here's my delegate code that works fine:
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedStep = appState.recipe.steps[sourceIndexPath.row]
appState.recipe.steps.remove(at: sourceIndexPath.row)
appState.recipe.steps.insert(movedStep, at: destinationIndexPath.row)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
appState.recipe.steps.remove(at: indexPath.row)
tblSteps.deleteRows(at: [indexPath], with: .automatic)
}
}
Notes:
I manually place this table view in edit mode through a UIBarButtonItem, and a cell can both be moved or deleted.
My data source is in my model, at appState.recipe.steps. The structure doesn't matter, just handling the array.
I set a Notification anytime this array is changed that triggers a reloadData() in this table view.
I don't see either of these delegate methods listed, so I'm posting this answer. If by chance it doesn't help you, I'll gladly delete this.

Swift 5 UITableViewCell : Expand one section and collapse the expanded section

I have implemented the following code to add expand/collapse feature to UITableView sections. When user click each section1, it expands and when we click the same section1 it collapses. But, I want the section1 to collapse, if I am expanding section2. How can I implement this feature to my code added below.
struct FaqData{
var faqHead = String()
var faqImage = String()
var questionArray : [(question : String, answer : String, answerurl : String)] = [(String,String,String)]()
var openSection = Bool()
}
var supportArray = [FaqData]()
func numberOfSections(in tableView: UITableView) -> Int {
return supportArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return 1
}
else{
if supportArray[section].openSection == true{
return supportArray[section].questionArray.count + 1
}else{
return 1
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportCenterID", for: indexPath) as! SupportCenterTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.faqCollection.reloadData()
return cell
}
else{
if indexPath.row == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportFaqID") as! SupportCenterFaqTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
let faqHead = supportArray[indexPath.section].faqHead
cell.imageText.text = faqHead.capitalized
cell.imageButton.setImage(UIImage(named: supportArray[indexPath.section].faqImage), for: .normal)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionID") as! SupportQuestionTableViewCell
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.isSelected = true
cell.questionLabel.text = "Q.\(indexPath.row) " + supportArray[indexPath.section].questionArray[indexPath.row - 1].question
cell.answerLabel.text = supportArray[indexPath.section].questionArray[indexPath.row - 1].answer
print(supportArray[indexPath.section].questionArray[indexPath.row - 1].answerurl)
if supportArray[indexPath.section].questionArray[indexPath.row - 1].answerurl == ""{
cell.urlButton.isHidden = true
}
else{
cell.urlButton.isHidden = false
}
cell.urlButton.isHidden = true
cell.urlButton.tag = indexPath.row
UserDefaults.standard.set(indexPath.section, forKey: "SectionValue")
cell.urlButton.addTarget(self, action: #selector(urlButtonClicked(_:)), for: .touchUpInside)
cell.layoutMargins = UIEdgeInsets.zero
return cell
}
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if supportArray[indexPath.section].openSection == true{
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = .white
cell.imageButton.tintColor = UIColor(hexString: "#D71B61")
cell.imageText.textColor = UIColor(hexString: "#D71B61")
}
}
supportArray[indexPath.section].openSection = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .fade)
}
else{
supportArray[indexPath.section].openSection = true
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .fade)
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Can anyone provide a solution for this?
do this in didselecterow method. This is the else case of your condition
// You will need to reload multiple sections. So make an array.
var reloadSections = [Int]()
// find already opened array
if let alreadyOpenSection = supportArray.firstIndex(where: { (faq) -> Bool in
return faq.openSection
}) {
// if found, toggle the openSections bit
supportArray[alreadyOpenSection].openSection = false
// add it to reload sections array
reloadSections.append(alreadyOpenSection)
}
supportArray[indexPath.section].openSection = true
reloadSections.append(indexPath.section)
// create index set with reload sections array
let sections = IndexSet.init(reloadSections)
tableView.reloadSections(sections, with: .fade)
// below code is same
if indexPath.section != 0{
if indexPath.row == 0{
let cell = tableView.cellForRow(at: indexPath) as! SupportCenterFaqTableViewCell
cell.faqView.backgroundColor = UIColor(hexString: "#D71B61")
cell.imageButton.tintColor = .white
cell.imageText.textColor = .white
}
}

How to hide the sections in the tableview after deleting a particular section from tableview?

I am having three sections (see the image) in which one section is to display the items and remaining two cells are designed by using stroyboard now if i delete all the items using delete button in first section then the remaining two sections need to be hidden and to display some text can anyone help me how to do this ?
func numberOfSections(in tableView: UITableView) -> Int{
// #warning Incomplete implementation, return the number of sections
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if (section == 0){
return itemsArray.count
}else{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! productTableViewCell
tableDetails.isHidden = false
myActivityIndicator.stopAnimating()
let arr = itemsArray[indexPath.row]
let urls = NSURL(string: arr["img"] as! String)
let data = NSData (contentsOf: urls! as URL)
cell.imageview.image = UIImage(data: data! as Data)
cell.nameLabel.text = arr["productName"]as! String
var price = arr["productPrice"] as! String
print(price)
var Quantity : Float = 1
let itemId : Int = arr["sku"] as! Int
print(itemId)
for aDic in CartArray{
if aDic["id"] == String(itemId){
Quantity = Float(String(aDic["quantity"]!))!
}
}
print(CartArray)
cell.stepper.value = Double(Int(Quantity))
cell.stepper.tag = indexPath.row
cell.stepper.addTarget(self, action: #selector(stepperValueChange(stepper:)), for:.valueChanged)
price = price.replacingOccurrences(of: "KD", with: "")
cartstring = String(Float(price)! * Quantity) + "0KD"
cell.priceLabel.text = cartstring
let quantityText = String(Quantity)
let endIndex = quantityText.index(quantityText.endIndex, offsetBy: -2)
let truncated = quantityText.substring(to: endIndex)
cell.quantityTextField.text = truncated
cell.price = price
cell.deleteButton.addTarget(self, action: #selector(deleteButtonAction(button:)), for: .touchUpInside)
cell.deleteButton.tag = indexPath.row
return cell
}else if indexPath.section == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: "couponcell", for: indexPath) as! CouponTableViewCell
cell.applyButton.addTarget(self, action: #selector(applyButtonAction(button:)), for: .touchUpInside)
return cell
}else {
let cell = tableView.dequeueReusableCell(withIdentifier: "checkout", for: indexPath) as! checkoutTableViewCell
cell.finalCartpriceLabel.text = total
return cell
}
}
func deleteButtonAction(button : UIButton) {
let buttonPosition = button.convert(CGPoint(), to: tableDetails)
let index = tableDetails.indexPathForRow(at: buttonPosition)
self.itemsArray.remove(at: (index?.row)!)
self.tableDetails.deleteRows(at: [index!], with: .automatic)
tableDetails.reloadData()
}
Modify your numberOfSections with:
func numberOfSections(in tableView: UITableView) -> Int {
if self.itemsArray.count > 0 {
return 3
}
//Show Message List is Empty
return 1
}
You can manage something like,
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
if (section == 0){
return itemsArray.count
}else{
if self.itemsArray.count == 0 {
return 0
}
else{
return 1
}
}
}
You can just check for self.itemsArray.count > 0 inside your func numberOfSections(in:) and show all the three sections for this condition. Otherwise, return only the first section and this will automatically hide the other two.
Example:
func numberOfSections(in tableView: UITableView) -> Int {
if self.itemsArray.count > 0 {
return 3
}
return 1
}
in numberOfSection datasource methods, check if itemArray has no elements, return just one section. In cellForRowAtIndexPath, check the same condition again, and show the empty text in this.
func numberOfSections(in tableView: UITableView) -> Int {
if(itemArray.count > 0)
{
if (section == 0){
return itemsArray.count
}else{
return 1
}
} else {
return 1;
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(itemArray.count > 0)
{
}else {
//Show empty text view
}
}
this code worked for me perfectly
func deleteButtonAction(button : UIButton) {
let buttonPosition = button.convert(CGPoint(), to: tableDetails)
let index = tableDetails.indexPathForRow(at: buttonPosition)
self.itemsArray.remove(at: (index?.row)!)
self.tableDetails.deleteRows(at: [index!], with: .automatic)
tableDetails.reloadData()
if (tableView(tableDetails, numberOfRowsInSection: 0) == 0){
tableDetails.isHidden = true
}
if (tableDetails.isHidden == true){
self.loadingLabel.textColor = UIColor.gray
self.loadingLabel.textAlignment = NSTextAlignment.center
self.loadingLabel.text = "Your shopping cart is empty"
self.loadingLabel.frame = CGRect(x: 130, y: 320, width: 140, height: 30)
view.addSubview(loadingLabel)
}
}

Prototype cells not displaying correctly

My tableView has two prototype cells which are programmed in the storyboard as below.
The identifiers are all correct another isn't a mistake between the IB and the storyboard as the identifiers link up. But when I build and run the project I get presented with the following screen (Note that on this run, semester.subjects and semester.activities are empty).
Also notice that when I click my first cell, nothing happens but when I click my second cell it changes to what I wanted it to be. My question is How does this happen? Also below is my cellForRowAt indexPath if you need it.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
let addCell = tableView.dequeueReusableCell(withIdentifier: "addCell", for: indexPath) as! AddSubjectTableViewCell
var cellToAdd = UITableViewCell()
switch indexPath.section {
case 0:
if indexPath.row < semester.subjects.count{
let subject = semester.subjects[indexPath.row]
cell.subjectColourView.backgroundColor = subject.colour
cell.subjectLabel.text = subject.name
cell.teacherLabel.text = subject.teacher
cellToAdd = cell
}
else if indexPath.row == semester.subjects.count {
cellToAdd = addCell
}
case 1:
if indexPath.row < semester.activities.count{
let activity = semester.activities[indexPath.row]
cell.subjectColourView.backgroundColor = activity.colour
cell.subjectLabel.text = activity.name
cell.teacherLabel.text = activity.teacher
cellToAdd = cell
}
else if indexPath.row == semester.activities.count {
cellToAdd = addCell
}
default:
break
}
print(cellToAdd.reuseIdentifier)
return cellToAdd
}
Here is the entire TVC
import UIKit
class SubjectTableViewController: UITableViewController {
var semester: Semester!
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
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 {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return semester.subjects.count + 1
case 1:
return semester.activities.count + 1
default:
return 0
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
return "Subjects"
case 1:
return "Extracurricular Activities"
default:
return nil
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
let addCell = tableView.dequeueReusableCell(withIdentifier: "addCell", for: indexPath) as! AddSubjectTableViewCell
var cellToAdd = UITableViewCell()
switch indexPath.section {
case 0:
if indexPath.row < semester.subjects.count{
let subject = semester.subjects[indexPath.row]
cell.subjectColourView.backgroundColor = subject.colour
cell.subjectLabel.text = subject.name
cell.teacherLabel.text = subject.teacher
cellToAdd = cell
}
else if indexPath.row == semester.subjects.count {
cellToAdd = addCell
}
case 1:
if indexPath.row < semester.activities.count{
let activity = semester.activities[indexPath.row]
cell.subjectColourView.backgroundColor = activity.colour
cell.subjectLabel.text = activity.name
cell.teacherLabel.text = activity.teacher
cellToAdd = cell
}
else if indexPath.row == semester.activities.count {
cellToAdd = addCell
}
default:
break
}
print(cellToAdd.reuseIdentifier)
return cellToAdd
}
}
The problem, for who knows what reason, is that the cell was denied outside of the switch.
if indexPath.row < semester.subjects.count{
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
let subject = semester.subjects[indexPath.row]
cell.subjectColourView.backgroundColor = subject.colour
cell.subjectLabel.text = subject.name
cell.teacherLabel.text = subject.teacher
cellToAdd = cell
}

Resources