29 мая 2012 г., 11:46 отEyal

Цель c - Лучшая практика для обработки события касания кнопки для кнопки пользовательского UITableViewCell

Как лучше обрабатывать событие касания кнопки для кнопкиUITableViewCell?

мои занятия: MyViewController, MyCustomCell

Я могу придумать три варианта:

First option- Иметь кнопку как свойствоMyCustomCellи затем добавьте цель к нему вMyViewController .m файл сMyViewController как цель.

MyViewController .m файл

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"customCell";

    MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
    cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    [cell.theButton addTarget:self
                       action:@selector(theButtonTapped:)
             forControlEvents:UIControlEventTouchUpInside];
    }

    // Configure the cell...    
    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)theButtonTapped:(UIButton *)sender
{
    MyCustomCell *selectedCell = (MyCustomCell *)sender.superview;

    if (selectedCell) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell];
        MyModel *selectedModel = [self.model objectAtIndex:indexPath.row]; 

        // do something with the model...
    }
}

Second option- Если пользовательская ячейка была создана в IB, установите для владельца файла пера значениеMyViewController, воплощать в жизньbuttonTapped: метод вMyViewController и подключите событие Touch Up Inside кbuttonTapped: метод.

Third option- если пользовательская ячейка не была создана в IB, добавьте цель к кнопке вMyCustomCell .m файл сMyCustomCell как цель.
ОпределитьMyCustomCellDelegate добавлять@property (nonatomic, assign) id<MyCustomCellDelegate> delegate вMyCustomCell и вызовите этого делегата, когда нажмете кнопку.
ЗадаватьMyViewController в качестве делегата ячейки при создании ячеек и реализацииMyCustomCellDelegate протокол.

MyCustomCell .h файл

@class MyCustomCell;  

@protocol MyCustomCellDelegate <NSObject>
- (void)buttonTappedOnCell:(MyCustomCell *)cell;
@end

@interface MyCustomCell : UITableViewCell

@property (nonatomic, retain) UIButton *theButton;
@property (nonatomic, assign) id<MyCustomCellDelegate> delegate;

@end

MyCustomCell .m файл

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        self.theButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        self.theButton.frame = CGRectMake(10,10,50,30);
        [self addSubview:self.theButton];

        [self.theButton addTarget:self
                           action:@selector(theButtonTapped:)
                 forControlEvents:UIControlEventTouchUpInside];
    }
    return self;
}

- (void)theButtonTapped:(UIButton *)sender
{
    [self.delegate buttonTappedOnCell:self];
}

MyViewController .m файл

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"customCell";

    MyCustomCell *cell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        cell.delegate = self;
    }

    // Configure the cell...    
    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}

- (void)buttonTappedOnCell:(MyCustomCell *)selectedCell
{
    if (selectedCell) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:selectedCell];
        MyModel *selectedModel = [self.model objectAtIndex:indexPath.row];

        // do something with the model...
    }
}

Ответы на вопрос(5)

25 окт. 2016 г., 05:23 отSourabh Sharma

Swift 3.0 Solution


cell.btnRequest.addTarget(self,action:#selector(buttonClicked(sender:)), for: .touchUpInside)

func buttonClicked(sender:UIButton) {

    let buttonRow = sender.tag
 }
29 мая 2012 г., 08:58 отKreiri

Сохранить строку ячейки какtag свойство вашей пользовательской кнопки.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // bla bla bla
    if (!cell)
    {
        //bla bla bla
        [cell.yourButton addTarget:self selector:@selector(yourButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    }
    // bla bla bla
    cell.yourButton.tag = indexPath.row;
}

-(void)yourButtonTapped:(id)sender
{
    int tag = [(UIButton *)sender tag];
    NSLog(@"tapped button in cell at row %i", tag);
}
14 мая 2016 г., 12:34 отduan

с моей точки зрения, нарушит строгость вашего кода. Кроме того, если у вас есть несколько разделов, использование тега определенно приведет к путанице в вашем коде.

Чтобы избежать этой проблемы, вы можете подклассUITableViewCell и держи егоindexPath свойство, чтобы ячейка знала свое точное положение.

Еще одна проблема, еслиUITableView вызывает API дляinsert илиdelete строка, вы должны обновить данные положения видимых ячеек

Я не думаю, что это лучшая практика.

Существует лучший способ.

Я настоятельно рекомендую использовать MVVM, когда вам приходится обрабатывать различные сенсорные события в вашей ячейке.

В этом шаблоне твой обычайUITableViewCell будет иметь пользовательскийCellViewModel. Этот класс будет отвечать за хранение всех данных, которые вы связываете с ячейкой, поэтому вы можете извлечь данные и поместить логику обработки событий в ячейку.

14 мая 2016 г., 17:52 отgnasher729

и в этот момент это подпредставление ячейки, которое является подпредставлением некоторого табличного представления.

Просто напишите метод, который принимает представление, идет вверх по цепочке суперпредставления, чтобы найти содержащую ячейку, идет дальше, чтобы найти представление таблицы, а затем запрашивает представление таблицы для indexPath ячейки.

Это намного проще и надежнее, чем хранить тег, содержащий строку, потому что вы не сталкиваетесь с проблемами при редактировании таблицы, и гораздо лучше иметь код, который определяет, какой это indexPath, когда вам нужен indexPath, а не в каком-то совершенно не связанном коде при создании ячейки.

14 мая 2016 г., 16:59 отkaushal

typedef void (^ActionBlock)(id sender);

@interface UIBlockButton : UIButton {
     ActionBlock _actionBlock;
 } 

-(void)handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock) action;
​@end

@implementation UIBlockButton

 -(void) handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock) action
    {
      _actionBlock = action;
      [self addTarget:self action:@selector(callActionBlock:) forControlEvents:event];
      }

  -(void) callActionBlock:(id)sender{
     _actionBlock(sender);
   }

@end

И делегат в виде таблицы:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (!cell)
    {
     cell.yourButton.tag = indexPath.row;// pass tag
     [cell.yourButton handleControlEvent:UIControlEventTouchUpInside withBlock:^(id sender) {
     // your selector action code
     NSLog(@"tapped button in cell at row %i",[(UIButton *)sender tag]);
     }];
   }  
}

ВАШ ОТВЕТ НА ВОПРОС