How to Get Index Path of Cell on Switch Change Event in Section Based Table View

How can I get index path of cell on switch change event in section based table view

In your custom cell add properties which help you identify the information the cell represents. Index path, indexes for your data model etc...

Then add a block property to the cell which you can call to tell a UITableView or any other piece of code when a cell switch changes. e.g.

@property (nonatomic,copy) void (^onSwitchChange)(UITableViewCell *cell);

Inside your custom cell code, add an action handler for the UISwitch. When it fires, call self.onSwitchChange(self) which will notify the code which registered an onSwitchChange block that a switch has changed and on which cell.

In your table view when you create the cell, set the onSwitchChange block as follows:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath (NSIndexPath *)indexPath
{
<snip>

YourUITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:yourCellIdentifier forIndexPath:indexPath];
cell.onSwitchChange=^(UITableViewCell *cellAffected){
// Add code to deal with the swicth switch using properties of cellAffected
... Your handler code here ...
}];

<snip>
}

This lets you handle all the changes in the table view controller. Hope this helps.

How can I keep track of the index path of a button in a table view cell?

I have created one Method for getting indexPath, Hope this will help you.

Create Button Action (aMethod:) in cellForRowAtIndexPath

-(void) aMethod:(UIButton *)sender
{
// Calling Magic Method which will return us indexPath.
NSIndexPath *indexPath = [self getButtonIndexPath:sender];

NSLog(@"IndexPath: %li", indexPath.row);
NSLog(@"IndexRow: %li", indexPath.section);
}

// Here is the Magic Method for getting button's indexPath

-(NSIndexPath *) getButtonIndexPath:(UIButton *) button
{
CGRect buttonFrame = [button convertRect:button.bounds toView:groupTable];
return [groupTable indexPathForRowAtPoint:buttonFrame.origin];
}

How to get the indexpath.row when an element is activated?

giorashc almost had it with his answer, but he overlooked the fact that cell's have an extra contentView layer. Thus, we have to go one layer deeper:

guard let cell = sender.superview?.superview as? YourCellClassHere else {
return // or fatalError() or whatever
}

let indexPath = itemTable.indexPath(for: cell)

This is because within the view hierarchy a tableView has cells as subviews which subsequently have their own 'content views' this is why you must get the superview of this content view to get the cell itself. As a result of this, if your button is contained in a subview rather than directly into the cell's content view, you'll have to go however many layers deeper to access it.

The above is one such approach, but not necessarily the best approach. Whilst it is functional, it assumes details about a UITableViewCell that Apple have never necessarily documented, such as it's view hierarchy. This could be changed in the future, and the above code may well behave unpredictably as a result.

As a result of the above, for longevity and reliability reasons, I recommend adopting another approach. There are many alternatives listed in this thread, and I encourage you to read down, but my personal favourite is as follows:

Hold a property of a closure on your cell class, have the button's action method invoke this.

class MyCell: UITableViewCell {
var button: UIButton!

var buttonAction: ((Any) -> Void)?

@objc func buttonPressed(sender: Any) {
self.buttonAction?(sender)
}
}

Then, when you create your cell in cellForRowAtIndexPath, you can assign a value to your closure.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! MyCell
cell.buttonAction = { sender in
// Do whatever you want from your button here.
}
// OR
cell.buttonAction = buttonPressed(closure: buttonAction, indexPath: indexPath) // <- Method on the view controller to handle button presses.
}

By moving your handler code here, you can take advantage of the already present indexPath argument. This is a much safer approach that the one listed above as it doesn't rely on undocumented traits.

How to pass state of UISwitch in prototype cell back to UITableView

First you need to create the call back in table view cell.

 class ProgrammeToogleTableViewCell: UITableViewCell {

@IBOutlet weak var switchUI: UISwitch!

// callback to get action of switch status
var callBackSwitchState:((Bool) -> (Void))?

// Create action for value change event on switch
@IBAction func switchAtValueChanged(programmeToggle: UISwitch) {
callBackSwitchState?(programmeToggle.isOn)
}
}

Now in your cellForRowAt data source method, you need to set the value for this callback that you just created to get the status for your switch:

In your table view class:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 
UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"ProgrammeToggleTableViewCell", for: indexPath) as? ProgrammeToogleTableViewCell
else { return UITableViewCell() }
cell.tag = indexPath.row

// Implement the callback to get the status of switch:
cell.callBackSwitchState = { isOn in
print("Your Switch status = \(isOn)")

// isOn is your switch status. You can update your object here.
}

// Your other code here ....
return cell
}

Allows to choose only one option switch button inside table view

You would want to add a property in your view controller that would keep track of the selected switch

var selectedSwitchIndex: Int?

And in your cellForRowAt method, set the selected switch to On and keep other switches off.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "answerListCell", for: indexPath) as! AnswerListTableViewCell
cell.separatorInset.right = cell.separatorInset.left
cell.answerList.optionSwitch.tag = indexPath.row
cell.answerList.optionSwitch.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
let isSelected = indexPath.row == selectedSwitchIndex
cell.answerList.optionSwitch.isOn = isSelected

return cell

And in your switchChanged method, set the selectedSwitchIndex property to switch index which is toggled and reload your table view.

@objc func switchChanged(_ sender: UISwitch!){
// you would want to save the index only when its set to on
guard sender.isOn else {
// setting the selectedSwitchIndex to nil if the switch is turned off
selectedSwitchIndex = nil
return
}
selectedSwitchIndex = sender.tag
tableView.reloadData()
}

Switch Statement on didSelectRowAt Function in Swift

try my code

var count = 0
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
count += 1
let cell = tableView.cellForRow(at: indexPath)
switch count {
case 1:
cell.cellLabel.text = "first time label changes"
case 2:
cell.cellLabel.text = "second time label changes"

default:
cell.cellLabel.text = "change the label"
}
}

if you need "first" when you touch it 3 times

 var count = 0
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
count += 1
if count > 2 {
count = 1
}
let cell = tableView.cellForRow(at: indexPath)
switch count {
case 1:
cell.cellLabel.text = "first time label changes"
case 2:
cell.cellLabel.text = "second time label changes"
default:
cell.cellLabel.text = "change the label"
}
}

How can i hide a Section when UISwitch is Changed

Try to change your code this way, Add one action with your UISwitch ValueChanged event and reload the tableView.

@IBAction func switchValueChange(sender: UISwitch) {
tableView.reloadData()
}

Now change your UITableViewDataSource method like this way

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if mySwitch.on {
return 3
}
else {
return 2
}
}

// set number for rows for each setion
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return self.going.count
}
if section == 1 {
if mySwitch.on {
return self.eventdays.count
}
else {
return self.others.count
}
}
if section == 2 {
return self.others.count
}

return 0
}

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Can Go?"
}
if section == 1 {
if mySwitch.on {
return "Days"
}
else {
return "Others"
}
}
if section == 2 {
return "Others"
}
return "Default Title"
}

What is the index path of a table view cell that is currently being rearranged (moved) by the user?

- (NSIndexPath *)tableView:(UITableView *)tableView          targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:    (NSIndexPath *)proposedDestinationIndexPath
{
if (proposedDestinationIndexPath.section != sourceIndexPath.section)
{
return sourceIndexPath;
}

return proposedDestinationIndexPath;
}

Do not forget to do another check in your tableView:moveRowAtIndexPath:toIndexPath: data source method as shown below, you do not want to run your application logic when the destination is similar to the source.

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath      *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
if(sourceIndexPath == destinationIndexPath)
{
return;
}

//application logic
}


Related Topics



Leave a reply



Submit