Referance Link that I have used
Here is my code
class ViewController: UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(true, animated: false)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
It was Work fine for the default UITableViewCell. But if I have do the same thing with Custom UITableViewCell then selection is not worling
Code with Custom Cell
class ViewController: UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(true, animated: false)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customcell", for: indexPath) as! ProductTblCell
cell.lblProductTitle?.text = "\(indexPath.row)"
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
ProductTblCell Calss
class ProductTblCell: UITableViewCell {
#IBOutlet weak var lblProductTitle: UILabel!
}
Can you please someone tell me what's going Wrong? Thanks in advance
Output
It was, as tends to be the case, my mistake
After searching a lot I realized the issue.
The problem was mostly we all set the cell's selectionStyle property to .none from Storyboard or programmatically to remove the background color of the cell during the selection.
Keep in mind that if you want to use the default selection or
multiple selections feature during the editing must you need to follow this
Set the Selection Style from Storyboard
You can also Set in table views cellForRowAt method
cell.selectionStyle = .none
To remove or change the background color of the cell for the selection you need to use this override method in UITableViewCell
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.backgroundColor = selected ? .gray : .white
}
Related
I'm trying to create an App but I'm struggling with a simple problem: How can I add a delete button to my custom cells?
I've created a NewCocoaTouchClass
I've created my custom design (added also a button for every cell) and provided the Outlets in the TableViewCellController
I managed to implement my custom cell to another viewController
I created a button on my viewController
I'd like that when the user taps on my new button, cell buttons will appear, and then I can delete cells singularly. When I create the IbAction I can't retrieve the cell code because the cell is defined only in my tableViewCode.
Thank in advance
Ps: I also implemented deleting cells by swipe but my custom cell design is incompatible with the standard rectangular delete option (this is awful).
TableViewCellController
import UIKit
class CustomTableTableViewCell: UITableViewCell {
static let identificatore = "CustomTableTableViewCell"
static func nib() -> UINib {
return UINib(nibName: "CustomTableTableViewCell", bundle: nil)
}
#IBOutlet weak var ImmagineCella: UIImageView!
#IBOutlet weak var TestoCella: UILabel!
#IBOutlet weak var Button: UIButton!
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
}
}
ViewController
import UIKit
class MaterieViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var materie : [String] = ["zoifvdhfdv", "szvzv", "zdvzfv", "zfdvbfdb", "bfzdfb"]
#IBOutlet weak var TableViewMaterie: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
TableViewMaterie.register(CustomTableTableViewCell.nib(), forCellReuseIdentifier: CustomTableTableViewCell.identificatore)
TableViewMaterie.delegate = self
TableViewMaterie.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return materie.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableTableViewCell.identificatore, for: indexPath) as! CustomTableTableViewCell
cell.TestoCella.text = materie[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 67.83
}
#IBAction func EditButton(_ sender: UIButton) {
}
}
This is the code I use in my project
func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String?
{
return "Delete"
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
//Add your code
}
}
You can write with add target
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableTableViewCell.identificatore, for: indexPath) as! CustomTableTableViewCell
cell.TestoCella.text = materie[indexPath.row]
cell. Button.tag = indexPath.row
cell. Button.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside)
return cell
}
func buttonClicked(sender: UIButton) {
let buttonRow = sender.tag
print(buttonRow)
}
UITableViewCell is crashing with "Unexpectedly found nil while implicitly unwrapping an Optional value" when i try to modify cell subviews.
Registering tableView cell
self.tableView.register(TravelTypeTableViewCell.self, forCellReuseIdentifier: "TravelCell")
tablView methods
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 224
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TravelCell", for: indexPath) as! TravelTypeTableViewCell
cell.travelTypeSegment.selectedSegmentIndex = 0
return cell
}
TableViewcell class
class TravelTypeTableViewCell: UITableViewCell {
#IBOutlet var travelTypeSegment: UISegmentedControl!
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
}
}
Storyboard images
Comment this
self.tableView.register(TravelTypeTableViewCell.self, forCellReuseIdentifier: "TravelCell")
As for prototype cells you shouldn't register them as this done automatically for them and make sure travelTypeSegment is connected in IB
I have this code:
class UserProfilViewController: UIViewController {
// Outlets
#IBOutlet weak var userProfileTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.title = "Profil"
}
}
// MARK: - Table View Data Source
extension UserProfilViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserProfilCell", for: indexPath)
return cell
}
}
My project in bitbucket: https://bitbucket.org/trifek/karta-nauka/src/master/
I placed one tableviewcell cell on the tableview (UserProfil.storyboard). I have a form on it that I would like to display in this cell. The problem is the cell does not display. Does anyone know how to fix it?
As per the code you have shared, Please change your code to following.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserProfilCell", for: indexPath) as! UserProfilTableViewCell
return cell
}
Let me know in case of any queries.
IMHO, first try to clear your requirements. If you want to display fix number of cells then you can simply use static cells. If your cells are dynamic i.e their number depends on some calculation or other logic, then you can use dynamic cell. While using dynamic cell, verify if you have registered it or not (if you are using xib for cell) and also verify for the cell identifier.
#Lukasz
Please use the below code for this.
class UserProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setUIComponents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func setUIComponents(){
registerNibs()
}
}
extension UserProfileViewController: UITableViewDelegate, UITableViewDataSource{
internal func registerNibs(){
tableView.register(UINib(nibName: String(describing: UserProfileTableCell.self), bundle: Bundle.main), forCellReuseIdentifier: kUserProfileCellReuseId)
}
//MARK: TableView Methods -
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sessionCell: UserProfileTableCell.self = tableView.dequeueReusableCell(withIdentifier: kUserProfileCellReuseId, for: indexPath) as! UserProfileTableCell.self
cell.titleLabel.text = “TEST”
return sessionCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
class UserProfileTableCell: UITableViewCell {
//Set the "kUserProfileCellReuseId" in nib to register identifier.
let kUserProfileCellReuseId = "kUserProfileCellReuseId"
//MARK: - Override Methods
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUIComponents()
}
private func setUIComponents(){
}
}
You never declare that your view controller conforms to the UITableViewDataSource or UITableViewDelegate protocols. Given that you don't do that, you would not be able to set your view controller as the data source or delegate of your table view.
My tableview looks like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 200
}
And my tableviewcell looks like this
class Cell: UITableViewCell {
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
}
}
When I change switch state on any cell and scroll. The switch for another cell periodically have state changed on scroll for other cells. Please help
You need to have data array with state for every switch and in your didSelect method change data model for switch then in cellForRow at get switch state from array and your viewController need to be SwitchControlDelegate
class UIViewController:SwitchControlDelegate{
var array = [Bool](count: 200, repeatedValue:false)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell
cell.switchControl.isOn = array[indexPath.row]
cell.switchDelegate = self
cell.index = indexPath.row
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 200
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
array[indexPath.row] = !array[indexPath.row]
}
func switchChangeStateWithIndex(index:Int){
array[index] = !array[index]
}
This will change switch state when you click on cell , if you need to change state when change switch control you will need delegate to update data model in viewController
In your cell file:
protocol SwitchControlDelegate: class {
func switchChangeStateWithIndex(index:Int)
}
class Cell: UITableViewCell {
var index:Int = 0
weak var switchDelegate: SwitchControlDelegate?
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
}
#IBAction func valueChanged(_ sender: AnyObject) {
switchDelegate?.switchChangeStateWithIndex(index:index)
}
}
You need to match action value change from your switch control with this function valueChanged , so every time when you change switch state cell need to call func value Changeed
Handle your switch control properly for each cell in,
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
so that when cell is dequeue, it handles each cell's switchControl properly.
Solution:
When you change state of switch control for cell, save that indexPath somewhere so that when you iterate through this indexPath in tableview cellForRowAt indexPath you set that state of switch again else set default state
So here is the structure of the TableView:
There is a main UITableView, and inside each UITableViewCell there is another UITableview
Screenshot:
Each of the UITableViewCells have been designed as Custom Views and have been added by loading it from the Nib in the cellForRowAtIndexPath function.
What I want to do is for any option selected in the inner Table Views I want to get the index path of the cell that the Table View is embeded in.
Document Layout:
I tried to follow the delegate approach mentioned by Paulw11 here:
swift: how to get the indexpath.row when a button in a cell is tapped?: StackOverflow
Note: The method suggested by Paulw11 works perfectly
Code(TableVC):
class TableVC: UITableViewController, QuestionCellDelegate {
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 tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 5
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 220.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("QuestionCell", owner: self, options: nil)?.first as! QuestionCell
cell.delegate = self
return cell
}
func sendCellInfo(cell: UITableViewCell) {
print(cell)
let indexPathForQuestion = tableView.indexPath(for: cell)
print(indexPathForQuestion)
}}
Code(QuestionCell):
protocol QuestionCellDelegate: class {
func sendCellInfo(cell: UITableViewCell)
}
class QuestionCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var optionsTableview: UITableView!
var delegate: QuestionCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.optionsTableview.delegate = self
self.optionsTableview.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("OptionsCell", owner: self, options: nil)?.first as! OptionsCell
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = optionsTableview.cellForRow(at: indexPath)
print("selectedCell")
self.delegate?.sendCellInfo(cell: selectedCell!)
}}
Code(OptionsCell):
class OptionsCell: UITableViewCell {
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
}}
Note: The current O/P is nil
Note: Code changed as per commented by pbasdf, realised the mistake
Found the solution due to pbasdf comment:
Delegate Function in TableVC:
func sendCellInfo(cell: UITableViewCell) {
/*** Take the cell passed and convert to a CGPoint wrt to TableView ***/
let cellPosition: CGPoint = cell.convert(cell.bounds.origin, to: self.tableView)
/*** wrt to CGPoint find index on current TableView ***/
/*** Returns as Section,Cell ***/
let indexPathForSelectedCell = (tableView.indexPathForRow(at: cellPosition)?.row)
print(indexPathForSelectedCell)
}
The following answer is added #Supratik Majumdar request for the logic which I said.
Supratik try using the following code, I hope you will get your need done.
//Initialize your question or answer in viewDidLoad or where ever you like to as shown below
self.questionArray = ["Question1", "Question2"]
self.optionArray = [["Option 1", "Option 2", "Option 3", "Option 4"], ["Option 1", "Option 2", "Option 3", "Option 4"]]
//Make us of the following tableview delegate & datasource code
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.questionArray.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.OptionArray[section].count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String {
return self.questionArray[section]
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let currentOptionArray = self.questionArray[section]
let currentOption = currentOptionArray[indexPath.row]
cell.textLabel.text = currentOption
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedIndex = indexPath
let selectedQuestionIndex = indexPath.section
let selectedOptionIndex = indexPath.row
//Make use of the data you need in the above values
}
Use this:
tableView.cellForRowAtIndexPath(YourIndexPath) as! OptionCell
You can do your own indexPath as global variable and filing it on didSelectRow method
YourIndexPath = indexPath