accessoryButtonTappedForRowWithIndexPath: not getting called

烂漫一生 提交于 2019-11-27 20:26:52
Coder

Did you just click on the cell to select it or did you actually click on the accessory button indicator on the cell? It isn't clear from your question.

accessoryButtonTappedForRowWithIndexPath is applicable when you click on the button icon within the cell and not when you select the cell.

Tom

The doc says that the method tableView:accessoryButtonTappedForRowWithIndexPath: is not called when an accessory view is set for the row at indexPath. The method is only called when the accessoryView property is nil and when one uses and set the accessoryType property to display a built-in accessory view.

As I understand it, accessoryView and accessoryType are mutually exclusive. When using accessoryType, the system will call tableView:accessoryButtonTappedForRowWithIndexPath: as expected, but you have to handle the other case by yourself.

The way Apple does this is shown in the Accessory sample project of the SDK. In the cellForRowAtIndexPath method of the dataSource delegate, they set a target/action to a custom accessory button. Since one can't pass the indexPath to the action, they call an auxiliary method to retrieve the corresponding indexPath and they pass the result to the delegate method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    ...

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    ...

    // set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
    [button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
    ...
    cell.accessoryView = button;

    return cell;
}


- (void)checkButtonTapped:(id)sender event:(id)event{
    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
    if (indexPath != nil){
        [self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
    }
}

For some reason, your setup seems to fall in the accessoryView case. Have you tried to set the accessoryType with code instead of using the Interface Builder ?

mdebeus

This seems very relevant...

Disclosure indicator: When this element is present, users know they can tap anywhere in the row to see the next level in the hierarchy or the choices associated with the list item. Use a disclosure indicator in a row when selecting the row results in the display of another list. Don’t use a disclosure indicator to reveal detailed information about the list item; instead, use a detail disclosure button for this purpose.

Detail disclosure button: Users tap this element to see detailed information about the list item. (Note that you can use this element in views other than table views, to reveal additional details about something; see “Detail Disclosure Buttons” for more information.) In a table view, use a detail disclosure button in a row to display details about the list item. Note that the detail disclosure button, unlike the disclosure indicator, can perform an action that is separate from the selection of the row. For example, in Phone Favorites, tapping the row initiates a call to the contact; tapping the detail disclosure button in the row reveals more information about the contact.

Converting the top answer to Swift 3:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    let unseletcedImage = UIImage(named: "<imagename>")
    let seletcedImage = UIImage(named: "<imagename>")
    let button = UIButton(type: .custom)
    // match the button's size with the image size
    let frame = CGRect(x: CGFloat(0.0), y: CGFloat(0.0), width: CGFloat((unseletcedImage?.size.width)!), height: CGFloat((unseletcedImage?.size.height)!))
    button.frame = frame
    button.setBackgroundImage(unseletcedImage, for: .normal)
    button.setBackgroundImage(seletcedImage, for: .selected)
    cell?.accessoryView = button
    let action = #selector(checkButtonTapped(sender:event:))
    (cell?.accessoryView as? UIButton)?.addTarget(self, action: action, for: .touchUpInside)
    ....
    return cell!

}

@objc func checkButtonTapped(sender: UIButton?, event: UIEvent) {
    let touches = event.allTouches
    let touch = touches!.first
    guard let touchPosition = touch?.location(in: self.tableView) else {
        return
    }
    if let indexPath = tableView.indexPathForRow(at: touchPosition) {
        tableView(self.tableView, accessoryButtonTappedForRowWith: indexPath)
    }
}
Avt

According to UITableViewCellAccessoryType's documentation it is expected behaviour:

typedef enum : NSInteger {    
UITableViewCellAccessoryNone,   
UITableViewCellAccessoryDisclosureIndicator,   
UITableViewCellAccessoryDetailDisclosureButton,   
UITableViewCellAccessoryCheckmark,   
UITableViewCellAccessoryDetailButton } UITableViewCellAccessoryType;

Constants UITableViewCellAccessoryNone The cell does not have any accessory view. This is the default value.

UITableViewCellAccessoryDisclosureIndicator The cell has an accessory control shaped like a chevron. This control indicates that tapping the cell triggers a push action. The control does not track touches.

UITableViewCellAccessoryDetailDisclosureButton The cell has an info button and a chevron image as content. This control indicates that tapping the cell allows the user to configure the cell’s contents. The control tracks touches.

UITableViewCellAccessoryCheckmark The cell has a check mark on its right side. This control does not track touches. The delegate of the table view can manage check marks in a section of rows (possibly limiting the check mark to one row of the section) in its tableView:didSelectRowAtIndexPath: method.

UITableViewCellAccessoryDetailButton The cell has an info button without a chevron. This control indicates that tapping the cell displays additional information about the cell’s contents. The control tracks touches.

drew is spot on.

If you change to 'DetailDisclosure' in Storyboard, then the method will fire. (xCode 4.6 DP3)

This is another way to handle the disclosure button using the storyboard. You should click the table view cell and goto the Connections Inspector. There is a section called Triggered Segues, and you can drag from the selection line to the UIViewController that you want to segue to. The segue will happen automatically and you can capture prepareForSegue to capture the notification when it does.
The function accessoryButtonTappedForRowWithIndexPath never gets called for the disclosure button. It only gets called for the detailed disclosure button.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!