Using a custom image for a UITableViewCell's accessoryView and having it respond to UITableViewDelegate

后端 未结 10 1993
独厮守ぢ
独厮守ぢ 2020-11-27 09:35

I\'m using a custom drawn UITableViewCell, including the same for the cell\'s accessoryView. My setup for the accessoryView happens by the way of something like

相关标签:
10条回答
  • 2020-11-27 09:41

    Swift 5

    This approach uses the UIButton.tag to store the indexPath using basic bit-shifting. The approach will work on 32 & 64 bit systems as long as you don't have more than 65535 sections or rows.

    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId")
        let accessoryButton = UIButton(type: .custom)
        accessoryButton.setImage(UIImage(named: "imageName"), for: .normal)
        accessoryButton.sizeToFit()
        accessoryButton.addTarget(self, action: #selector(handleAccessoryButton(sender:)), for: .touchUpInside)
    
        let tag = (indexPath.section << 16) | indexPath.row
        accessoryButton.tag = tag
        cell?.accessoryView = accessoryButton
    
    }
    
    @objc func handleAccessoryButton(sender: UIButton) {
        let section = sender.tag >> 16
        let row = sender.tag & 0xFFFF
        // Do Stuff
    }
    
    0 讨论(0)
  • 2020-11-27 09:42

    Sadly that method doesn't get called unless the internal button type provided when you use one of the predefined types is tapped. To use your own, you'll have to create your accessory as a button or other UIControl subclass (I'd recommend a button using -buttonWithType:UIButtonTypeCustom and setting the button's image, rather than using a UIImageView).

    Here's some things I use in Outpost, which customizes enough of the standard widgets (just slightly, to match our teal colouring) that I wound up doing my own UITableViewController intermediary subclass to hold utility code for all other table views to use (they now subclass OPTableViewController).

    Firstly, this function returns a new detail disclosure button using our custom graphic:

    - (UIButton *) makeDetailDisclosureButton
    {
        UIButton * button = [UIButton outpostDetailDisclosureButton];
    
    [button addTarget: self
                   action: @selector(accessoryButtonTapped:withEvent:)
         forControlEvents: UIControlEventTouchUpInside];
    
        return ( button );
    }
    

    The button will call this routine when it's done, which then feeds the standard UITableViewDelegate routine for accessory buttons:

    - (void) accessoryButtonTapped: (UIControl *) button withEvent: (UIEvent *) event
    {
        NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: self.tableView]];
        if ( indexPath == nil )
            return;
    
        [self.tableView.delegate tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
    }
    

    This function locates the row by getting the location in the table view of a touch from the event provided by the button and asking the table view for the index path of the row at that point.

    0 讨论(0)
  • 2020-11-27 09:43
    1. Define a macro for tags of buttons:

      #define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax
      
    2. Create button and set the cell.accessoryView when creating a cell

      UIButton *accessoryButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
      accessoryButton.frame = CGRectMake(0, 0, 30, 30);
      [accessoryButton addTarget:self action:@selector(accessoryButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
      cell.accessoryView = accessoryButton;
      
    3. Set cell.accessoryView.tag by indexPath in UITableViewDataSource method -tableView:cellForRowAtIndexPath:

      cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row;
      
    4. Event handler for buttons

      - (void) accessoryButtonTapped:(UIButton *)button {
          NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag % AccessoryViewTagSinceValue
                                                      inSection:button.tag / AccessoryViewTagSinceValue];
      
          [self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
      }
      
    5. Implement the UITableViewDelegate method

      - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
          // do sth.
      }
      
    0 讨论(0)
  • 2020-11-27 09:44

    An extension to Jim Dovey's answer above:

    Be careful when you use a UISearchBarController with your UITableView. In that case you want to check for self.searchDisplayController.active and use self.searchDisplayController.searchResultsTableViewinstead of self.tableView. Otherwise you'll get unexpected results when the searchDisplayController is active, especially when the search results are scrolled.

    For example:

    - (void) accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event
    {
        UITableView* tableView = self.tableView;
        if(self.searchDisplayController.active)
            tableView = self.searchDisplayController.searchResultsTableView;
    
        NSIndexPath * indexPath = [tableView indexPathForRowAtPoint:[[[event touchesForView:button] anyObject] locationInView:tableView]];
        if(indexPath)
           [tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
    }
    
    0 讨论(0)
  • 2020-11-27 09:45

    With yanchenko approach I had to add: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];

    If you're using xib file to customise your tableCell then initWithStyle:reuseIdentifier: wont get called.

    Instead override:

    -(void)awakeFromNib
    {
    //Put your code here 
    
    [super awakeFromNib];
    
    }
    
    0 讨论(0)
  • 2020-11-27 09:46

    You must use a UIControl to properly get event dispatch (for instance a UIButton) instead of simple UIView/UIImageView.

    0 讨论(0)
提交回复
热议问题