Использование пользовательского изображения для a ccessoryView UITableViewCell и предоставление ему ответа на UITableViewDelegate
Я использую пользовательский нарисованный UITableViewCell, в том числе и для ячейки accessoryView
, Моя настройка для accessoryView происходит примерно так:
UIImage *accessoryImage = [UIImage imageNamed:@"accessoryDisclosure.png"];
UIImageView *accImageView = [[UIImageView alloc] initWithImage:accessoryImage];
accImageView.userInteractionEnabled = YES;
[accImageView setFrame:CGRectMake(0, 0, 28.0, 28.0)];
self.accessoryView = accImageView;
[accImageView release];
Также, когда ячейка инициализируется, используя initWithFrame:reuseIdentifier:
Я гарантированно установил следующее свойство:
self.userInteractionEnabled = YES;
К сожалению, в моем UITableViewDelegate, мой tableView:accessoryButtonTappedForRowWithIndexPath:
метод (попробуйте повторить это 10 раз) не срабатывает. Делегат определенно подключен правильно.
Что может быть пропущено?
Спасибо всем.
9 ответов
К сожалению, этот метод не вызывается, пока не будет нажат внутренний тип кнопки, предоставленный при использовании одного из предопределенных типов. Чтобы использовать свой собственный, вам нужно создать аксессуар в виде кнопки или другого подкласса UIControl (я бы порекомендовал кнопку, используя -buttonWithType:UIButtonTypeCustom
и установка изображения кнопки, а не использование UIImageView).
Вот некоторые вещи, которые я использую в Outpost, который настраивает достаточное количество стандартных виджетов (чуть-чуть, чтобы они соответствовали нашей окраске бирюзового цвета), которые я использовал для создания своего собственного промежуточного подкласса UITableViewController для хранения служебного кода для всех других табличных представлений (они теперь подклассы) OPTableViewController).
Во-первых, эта функция возвращает новую кнопку раскрытия подробностей, используя нашу собственную графику:
- (UIButton *) makeDetailDisclosureButton
{
UIButton * button = [UIButton outpostDetailDisclosureButton];
[button addTarget: self
action: @selector(accessoryButtonTapped:withEvent:)
forControlEvents: UIControlEventTouchUpInside];
return ( button );
}
Кнопка вызовет эту подпрограмму, когда это будет сделано, которая затем передает стандартную подпрограмму UITableViewDelegate для дополнительных кнопок:
- (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];
}
Эта функция определяет местоположение строки, получая местоположение в табличном представлении касания из события, обеспеченного кнопкой, и запрашивая в табличном представлении путь индекса строки в этой точке.
Я нашел этот сайт очень полезным: пользовательский вид аксессуаров для вашего uitableview в iphone
Короче говоря, используйте это в cellForRowAtIndexPath:
:
UIImage *image = (checked) ? [UIImage imageNamed:@"checked.png"] : [UIImage imageNamed:@"unchecked.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame;
[button setBackgroundImage:image forState:UIControlStateNormal];
[button addTarget:self action:@selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
Затем реализуйте этот метод:
- (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];
}
}
Мой подход заключается в создании UITableViewCell
подкласс и инкапсулировать логику, которая будет вызывать обычную UITableViewDelegate
внутри метод.
// CustomTableViewCell.h
@interface CustomTableViewCell : UITableViewCell
- (id)initForIdentifier:(NSString *)reuseIdentifier;
@end
// CustomTableViewCell.m
@implementation CustomTableViewCell
- (id)initForIdentifier:(NSString *)reuseIdentifier;
{
// the subclass specifies style itself
self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
if (self) {
// get the button elsewhere
UIButton *accBtn = [ViewFactory createTableViewCellDisclosureButton];
[accBtn addTarget: self
action: @selector(accessoryButtonTapped:withEvent:)
forControlEvents: UIControlEventTouchUpInside];
self.accessoryView = accBtn;
}
return self;
}
#pragma mark - private
- (void)accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event
{
UITableViewCell *cell = (UITableViewCell*)button.superview;
UITableView *tableView = (UITableView*)cell.superview;
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
[tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}
@end
Расширение ответа Джима Голубя выше:
Будьте осторожны при использовании UISearchBarController с вашим UITableView. В этом случае вы хотите проверить self.searchDisplayController.active
и использовать self.searchDisplayController.searchResultsTableView
вместо self.tableView
, В противном случае вы получите неожиданные результаты, когда searchDisplayController активен, особенно когда результаты поиска прокручиваются.
Например:
- (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];
}
При нажатии кнопки ее можно вызвать следующим методом внутри подкласса UITableViewCell.
-(void)buttonTapped{
// perform an UI updates for cell
// grab the table view and notify it using the delegate
UITableView *tableView = (UITableView *)self.superview;
[tableView.delegate tableView:tableView accessoryButtonTappedForRowWithIndexPath:[tableView indexPathForCell:self]];
}
Определите макрос для тегов кнопок:
#define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax
Создать кнопку и установить cell.accessoryView при создании ячейки
UIButton *accessoryButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; accessoryButton.frame = CGRectMake(0, 0, 30, 30); [accessoryButton addTarget:self action:@selector(accessoryButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; cell.accessoryView = accessoryButton;
Установите cell.accessoryView.tag с помощью indexPath в методе UITableViewDataSource -tableView:cellForRowAtIndexPath:
cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row;
Обработчик событий для кнопок
- (void) accessoryButtonTapped:(UIButton *)button { NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag % AccessoryViewTagSinceValue inSection:button.tag / AccessoryViewTagSinceValue]; [self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath]; }
Реализуйте метод UITableViewDelegate
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath { // do sth. }
Вы должны использовать UIControl
правильно получить отправку события (например, UIButton
) вместо простого UIView/UIImageView
,
С подходом Янченко я должен был добавить: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];
Если вы используете файл xib для настройки вашего tableCell, тогда initWithStyle:reuseIdentifier: не будет вызван.
Вместо этого переопределите:
-(void)awakeFromNib
{
//Put your code here
[super awakeFromNib];
}
Swift 5
Этот подход использует UIButton.tag
хранить indexPath с использованием базового сдвига битов. Подход будет работать на 32- и 64-битных системах, если у вас не более 65535 разделов или строк.
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
}
Начиная с iOS 3.2 вы можете избежать кнопок, которые рекомендуют другие, и вместо этого использовать ваш UIImageView с распознавателем жестов касания. Обязательно включите взаимодействие с пользователем, которое по умолчанию отключено в UIImageViews.