セルのaccessoryView
と同じものを含む、カスタム描画のUITableViewCellを使用しています。 accessoriesViewのセットアップは、次のような方法で行われます。
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回繰り返してみてください)がトリガーされません。デリゲートは間違いなく適切に接続されています。
おそらく何が欠けているのでしょうか?
皆さんありがとう。
残念ながら、事前定義されたタイプの1つを使用するときに提供される内部ボタンタイプがタップされない限り、そのメソッドは呼び出されません。独自のものを使用するには、ボタンまたは他のUIControlサブクラスとしてアクセサリを作成する必要があります(UIImageViewを使用するのではなく、-buttonWithType:UIButtonTypeCustom
を使用してボタンの画像を設定するボタンをお勧めします)。
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];
}
この関数は、ボタンによって提供されるイベントからタッチのテーブルビュー内の位置を取得し、その時点で行のインデックスパスをテーブルビューに要求することにより、行を見つけます。
このウェブサイトは非常に役立つことがわかりました: iphoneでのuitableviewのカスタムアクセサリービュー
要するに、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
上記のJim Doveyの答えの拡張:
UITableViewでUISearchBarControllerを使用するときは注意してください。その場合、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];
}
ボタンのタグのマクロを定義します。
#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;
UITableViewDataSourceメソッドのindexPathでcell.accessoryView.tagを設定します-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.
}
ボタンをタップすると、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]];
}
イベントディスパッチを適切に取得するには、単純なUIView/UIImageView
の代わりにUIControl
を使用する必要があります(たとえば、UIButton
)。
Yanchenkoアプローチでは、次を追加する必要がありました:[accBtn setFrame:CGRectMake(0, 0, 20, 20)];
Xibファイルを使用してtableCellをカスタマイズしている場合、initWithStyle:reuseIdentifier:は呼び出されません。
代わりにオーバーライド:
-(void)awakeFromNib
{
//Put your code here
[super awakeFromNib];
}
IOS 3.2では、ここで他の人が推奨しているボタンを避け、代わりにUIImageViewをタップジェスチャレコグナイザーで使用できます。 UIImageViewsではデフォルトでオフになっているユーザーインタラクションを有効にしてください。
Swift 5
このアプローチでは、UIButton.tag
を使用して、基本的なビットシフトを使用してindexPathを格納します。 65535を超えるセクションまたは行がない限り、このアプローチは32ビットおよび64ビットシステムで機能します。
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
}