UITableView에서 어떤 UIButton이 눌렸는지 감지
-
05-07-2019 - |
문제
나는 UITableView
5개로 UITableViewCells
.각 셀에는 UIButton
이는 다음과 같이 설정됩니다.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
[cell autorelelase];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
[button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:1];
[cell.contentView addSubview:button];
[button release];
}
UIButton *button = (UIButton *)[cell viewWithTag:1];
[button setTitle:@"Edit" forState:UIControlStateNormal];
return cell;
}
내 질문은 이것입니다:에서 buttonPressedAction:
방법, 어떤 버튼을 눌렀는지 어떻게 알 수 있나요?태그 사용을 고려해 보았지만 이것이 최선의 경로인지 잘 모르겠습니다.어떻게든 태그를 달 수 있었으면 좋겠어요 indexPath
컨트롤에.
- (void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
// how do I know which button sent this message?
// processing button press for this row requires an indexPath.
}
이 작업을 수행하는 표준 방법은 무엇입니까?
편집하다:
나는 다음을 수행하여 그것을 해결했습니다.이것이 표준 방법인지 아니면 더 좋은 방법이 있는지 의견을 듣고 싶습니다.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
[cell autorelelase];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
[button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button];
[button release];
}
UIButton *button = (UIButton *)[cell.contentView.subviews objectAtIndex:0];
[button setTag:indexPath.row];
[button setTitle:@"Edit" forState:UIControlStateNormal];
return cell;
}
- (void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
int row = button.tag;
}
주목해야 할 중요한 점은 셀이 대신 대기열에서 제거될 수 있으므로 셀 생성 시 태그를 설정할 수 없다는 것입니다.매우 더러운 느낌입니다.더 좋은 방법이 있어야 합니다.
해결책
애플에서 부속물 샘플 다음 방법이 사용됩니다.
[button addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
그런 다음 터치 핸들러 터치 좌표 검색되고 인덱스 경로가 해당 좌표에서 계산됩니다.
- (void)checkButtonTapped:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
if (indexPath != nil)
{
...
}
}
다른 팁
Superview의 수퍼 뷰를 사용하여 셀의 인덱스 경로에 대한 참조를 얻는 방법이 완벽하게 작동했습니다. 팁은 iphonedevbook.com (macnsmith)에 감사합니다 링크 텍스트
-(void)buttonPressed:(id)sender {
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...
}
내가하는 방법은 다음과 같습니다. 간단하고 간결한 :
- (IBAction)buttonTappedAction:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero
toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
...
}
이 문제에 대한 좋은 해결책을 다른 곳에서 찾았습니다. 버튼에 태그를 엉망으로 만들지 않았습니다.
- (void)buttonPressedAction:(id)sender {
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
// do stuff with the indexPath...
}
같은 정보를 보내는 것은 어떻습니까? NSIndexPath
에서 UIButton
런타임 주입 사용.
1) 가져 오기에서 런타임이 필요합니다
2) 정적 상수를 추가하십시오
3) 추가 NSIndexPath
런타임의 버튼에 다음을 사용합니다.
(void) setmetadata : (id) target withobject : (id) newobj
4) 버튼을 누르면 다음을 사용하여 메타 데이터를 얻습니다.
(ID) 메타 데이터 : (ID) 대상
즐기다
#import <objc/runtime.h>
static char const * const kMetaDic = "kMetaDic";
#pragma mark - Getters / Setters
- (id)metaData:(id)target {
return objc_getAssociatedObject(target, kMetaDic);
}
- (void)setMetaData:(id)target withObject:(id)newObj {
objc_setAssociatedObject(target, kMetaDic, newObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#On the cell constructor
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
....
[btnSocial addTarget:self
action:@selector(openComments:)
forControlEvents:UIControlEventTouchUpInside];
#add the indexpath here or another object
[self setMetaData:btnSocial withObject:indexPath];
....
}
#The action after button been press:
- (IBAction)openComments:(UIButton*)sender{
NSIndexPath *indexPath = [self metaData:sender];
NSLog(@"indexPath: %d", indexPath.row);
//Reuse your indexpath Now
}
할 (@vladimir)의 대답은 신속합니다.
var buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView)
var indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!
확인하지만 indexPath != nil
나에게 손가락을 줘 ... "nsindexpath는 nsstring의 하위 유형이 아니다"
func buttonAction(sender:UIButton!)
{
var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tablevw)
let indexPath = self.tablevw.indexPathForRowAtPoint(position)
let cell: TableViewCell = tablevw.cellForRowAtIndexPath(indexPath!) as TableViewCell
println(indexPath?.row)
println("Button tapped")
}
나는 당신이 말한 것처럼 태그 속성을 사용하여 다음과 같이 태그를 설정합니다.
[button setTag:indexPath.row];
그런 다음 버튼 압박 조치 내부에 태그를 가져옵니다.
((UIButton *)sender).tag
또는
UIButton *button = (UIButton *)sender;
button.tag;
나는 태그 방식을 좋아하지만 ... 어떤 이유로 든 태그를 사용하고 싶지 않다면 멤버를 만들 수 있습니다. NSArray
미리 미드 버튼 :
NSArray* buttons ;
그런 다음 테이블 뷰를 렌더링하기 전에 버튼을 만들고 배열로 밀어 넣으십시오.
그런 다음 내부 tableView:cellForRowAtIndexPath:
할 수있는 기능 :
UIButton* button = [buttons objectAtIndex:[indexPath row] ] ;
[cell.contentView addSubview:button];
그런 다음 buttonPressedAction:
기능, 할 수 있습니다
- (void)buttonPressedAction:(id)sender {
UIButton* button = (UIButton*)sender ;
int row = [buttons indexOfObject:button] ;
// Do magic
}
섹션을 처리하려면 - NSIndexPath를 사용자 정의 UitableViewCell에 저장했습니다.
clkindexpriceSheadertableViewCell.xib에서
ib에서 xib에 uibutton을 추가 - 액션을 추가하지 마십시오!
outlet @property (retain, nonomic) iboutlet uibitton *buttonindexectionclose를 추가합니다.
Ctrl+IB에서 작업을 드래그하지 마십시오 (아래 코드에서 완료)
@interface CLKIndexPricesHEADERTableViewCell : UITableViewCell
...
@property (retain, nonatomic) IBOutlet UIButton *buttonIndexSectionClose;
@property (nonatomic, retain) NSIndexPath * indexPathForCell;
@end
ViewForHeaderItsection에서 (Cellforrow에서도 작동해야합니다 ....
- viewForHeaderInSection is called for each section 1...2...3
- get the cell CLKIndexPricesHEADERTableViewCell
- getTableRowHEADER just does the normal dequeueReusableCellWithIdentifier
- STORE the indexPath IN the UITableView cell
- indexPath.section = (NSInteger)section
- indexPath.row = 0 always (we are only interested in sections)
- (UIView *) tableView:(UITableView *)tableView1 viewForHeaderInSection:(NSInteger)section {
//Standard method for getting a UITableViewCell
CLKIndexPricesHEADERTableViewCell * cellHEADER = [self getTableRowHEADER];
... 섹션을 사용하여 셀 데이터를 얻으십시오.
... 채우십시오
indexName = ffaIndex.routeCode;
indexPrice = ffaIndex.indexValue;
//
[cellHEADER.buttonIndexSectionClose addTarget:self
action:@selector(buttonDELETEINDEXPressedAction:forEvent:)
forControlEvents:UIControlEventTouchUpInside];
cellHEADER.indexPathForCell = [NSIndexPath indexPathForRow:0 inSection:section];
return cellHEADER;
}
사용자가 섹션 헤더에서 삭제 버튼을 누르면이 호출
- (void)buttonDELETEINDEXPressedAction:(id)sender forEvent:(UIEvent *)event
{
NSLog(@"%s", __PRETTY_FUNCTION__);
UIView * parent1 = [sender superview]; // UiTableViewCellContentView
//UIView *myContentView = (UIView *)parent1;
UIView * parent2 = [parent1 superview]; // custom cell containing the content view
//UIView * parent3 = [parent2 superview]; // UITableView containing the cell
//UIView * parent4 = [parent3 superview]; // UIView containing the table
if([parent2 isMemberOfClass:[CLKIndexPricesHEADERTableViewCell class]]){
CLKIndexPricesHEADERTableViewCell *myTableCell = (CLKIndexPricesHEADERTableViewCell *)parent2;
//UITableView *myTable = (UITableView *)parent3;
//UIView *mainView = (UIView *)parent4;
NSLog(@"%s indexPath.section,row[%d,%d]", __PRETTY_FUNCTION__, myTableCell.indexPathForCell.section,myTableCell.indexPathForCell.row);
NSString *key = [self.sortedKeysArray objectAtIndex:myTableCell.indexPathForCell.section];
if(key){
NSLog(@"%s DELETE object at key:%@", __PRETTY_FUNCTION__,key);
self.keyForSectionIndexToDelete = key;
self.sectionIndexToDelete = myTableCell.indexPathForCell.section;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Remove Index"
message:@"Are you sure"
delegate:self
cancelButtonTitle:@"No"
otherButtonTitles:@"Yes", nil];
alertView.tag = kALERTVIEW_REMOVE_ONE_INDEX;
[alertView show];
[alertView release];
//------
}else{
NSLog(@"ERROR: [%s] key is nil for section:%d", __PRETTY_FUNCTION__,myTableCell.indexPathForCell.section);
}
}else{
NSLog(@"ERROR: [%s] CLKIndexPricesHEADERTableViewCell not found", __PRETTY_FUNCTION__);
}
}
이 예에서는 삭제 버튼을 추가하여 UIalerTView를 표시해야합니다.
섹션과 키를 VC의 IVAR 섹션에 대한 정보 저장 정보에 저장합니다.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if(alertView.tag == kALERTVIEW_REMOVE_ONE_INDEX){
if(buttonIndex==0){
//NO
NSLog(@"[%s] BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex);
//do nothing
}
else if(buttonIndex==1){
//YES
NSLog(@"[%s] BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex);
if(self.keyForSectionIndexToDelete != nil){
//Remove the section by key
[self.indexPricesDictionary removeObjectForKey:self.keyForSectionIndexToDelete];
//sort the keys so sections appear alphabetically/numbericsearch (minus the one we just removed)
[self updateTheSortedKeysArray];
//Delete the section from the table using animation
[self.tableView beginUpdates];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:self.sectionIndexToDelete]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
//required to trigger refresh of myTableCell.indexPathForCell else old values in UITableViewCells
[self.tableView reloadData];
}else{
NSLog(@"ERROR: [%s] OBJECT is nil", __PRETTY_FUNCTION__);
}
}
else {
NSLog(@"ERROR: [%s] UNHANDLED BUTTON:%d", __PRETTY_FUNCTION__,buttonIndex);
}
}else {
NSLog(@"ERROR: [%s] unhandled ALERTVIEW TAG:%d", __PRETTY_FUNCTION__,alertView.tag);
}
}
A better way would be to subclass your button and add a indexPath property to it.
//Implement a subclass for UIButton.
@interface NewButton:UIButton
@property(nonatomic, strong) NSIndexPath *indexPath;
Make your button of type NewButton in the XIB or in the code whereever you are initializing them.
Then in the cellForRowAtIndexPath put the following line of code.
button.indexPath = indexPath;
return cell; //As usual
Now in your IBAction
-(IBAction)buttonClicked:(id)sender{
NewButton *button = (NewButton *)sender;
//Now access the indexPath by buttons property..
NSIndexPath *indexPath = button.indexPath; //:)
}
Swift 4.2 및 iOS 12를 사용하면 하나를 선택할 수 있습니다. 5 완전한 예제 다음 문제를 해결하기 위해.
#1. 사용 UIView
'에스 convert(_:to:)
그리고 UITableView
'에스 indexPathForRow(at:)
import UIKit
private class CustomCell: UITableViewCell {
let button = UIButton(type: .system)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
button.setTitle("Tap", for: .normal)
contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
button.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1).isActive = true
button.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: contentView.leadingAnchor, multiplier: 1).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.button.addTarget(self, action: #selector(customCellButtonTapped), for: .touchUpInside)
return cell
}
@objc func customCellButtonTapped(_ sender: UIButton) {
let point = sender.convert(CGPoint.zero, to: tableView)
guard let indexPath = tableView.indexPathForRow(at: point) else { return }
print(indexPath)
}
}
#2. 사용 UIView
'에스 convert(_:to:)
그리고 UITableView
'에스 indexPathForRow(at:)
(대안)
이것은 우리가 통과하는 이전 예제의 대안입니다. nil
~로 target
매개 변수 addTarget(_:action:for:)
. 이런 식으로, 첫 번째 응답자가 동작을 구현하지 않으면 적절한 구현이 발견 될 때까지 응답자 체인의 다음 응답자에게 전송됩니다.
import UIKit
private class CustomCell: UITableViewCell {
let button = UIButton(type: .system)
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
button.setTitle("Tap", for: .normal)
button.addTarget(nil, action: #selector(TableViewController.customCellButtonTapped), for: .touchUpInside)
contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
button.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1).isActive = true
button.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: contentView.leadingAnchor, multiplier: 1).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
return cell
}
@objc func customCellButtonTapped(_ sender: UIButton) {
let point = sender.convert(CGPoint.zero, to: tableView)
guard let indexPath = tableView.indexPathForRow(at: point) else { return }
print(indexPath)
}
}
#삼. 사용 UITableView
'에스 indexPath(for:)
그리고 대의원 패턴
이 예에서는 View Controller를 셀 대의원으로 설정했습니다. 셀의 버튼이 두드리면 대의원의 적절한 방법으로 호출을 트리거합니다.
import UIKit
protocol CustomCellDelegate: AnyObject {
func customCellButtonTapped(_ customCell: CustomCell)
}
class CustomCell: UITableViewCell {
let button = UIButton(type: .system)
weak var delegate: CustomCellDelegate?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
button.setTitle("Tap", for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
button.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1).isActive = true
button.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: contentView.leadingAnchor, multiplier: 1).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func buttonTapped(sender: UIButton) {
delegate?.customCellButtonTapped(self)
}
}
import UIKit
class TableViewController: UITableViewController, CustomCellDelegate {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.delegate = self
return cell
}
// MARK: - CustomCellDelegate
func customCellButtonTapped(_ customCell: CustomCell) {
guard let indexPath = tableView.indexPath(for: customCell) else { return }
print(indexPath)
}
}
#4. 사용 UITableView
'에스 indexPath(for:)
그리고 대표단 폐쇄
이것은 버튼 탭을 처리하기 위해 프로토콜 방지 선언 대신 클로저를 사용하는 이전 예제의 대안입니다.
import UIKit
class CustomCell: UITableViewCell {
let button = UIButton(type: .system)
var buttontappedClosure: ((CustomCell) -> Void)?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
button.setTitle("Tap", for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
contentView.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
button.topAnchor.constraint(equalToSystemSpacingBelow: contentView.topAnchor, multiplier: 1).isActive = true
button.leadingAnchor.constraint(greaterThanOrEqualToSystemSpacingAfter: contentView.leadingAnchor, multiplier: 1).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func buttonTapped(sender: UIButton) {
buttontappedClosure?(self)
}
}
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.buttontappedClosure = { [weak tableView] cell in
guard let indexPath = tableView?.indexPath(for: cell) else { return }
print(indexPath)
}
return cell
}
}
#5. 사용 UITableViewCell
'에스 accessoryType
그리고 UITableViewDelegate
'에스 tableView(_:accessoryButtonTappedForRowWith:)
버튼이 a UITableViewCell
'표준 액세서리 제어, 모든 탭이 호출을 유발합니다. UITableViewDelegate
'에스 tableView(_:accessoryButtonTappedForRowWith:)
, 관련 인덱스 경로를 얻을 수 있습니다.
import UIKit
private class CustomCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
accessoryType = .detailButton
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
return cell
}
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
print(indexPath)
}
}
@cocoanut에게 감사합니다
Superview의 수퍼 뷰를 사용하여 셀의 인덱스 경로에 대한 참조를 얻는 방법이 완벽하게 작동했습니다. 팁 링크 텍스트에 대한 iphonedevbook.com (macnsmith)에 감사드립니다.
-(void)buttonPressed:(id)sender {
UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...
}
태그 패턴을 사용할 수 있습니다.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
[cell autorelelase];
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10, 5, 40, 20)];
[button addTarget:self action:@selector(buttonPressedAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTag:[indexPath row]]; //use the row as the current tag
[cell.contentView addSubview:button];
[button release];
}
UIButton *button = (UIButton *)[cell viewWithTag:[indexPath row]]; //use [indexPath row]
[button setTitle:@"Edit" forState:UIControlStateNormal];
return cell;
}
- (void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
//button.tag has the row number (you can convert it to indexPath)
}
내가 뭔가를 놓치고 있습니까? 발신자를 사용하여 버튼을 식별 할 수 없습니다. 발신자는 다음과 같은 정보를 제공합니다.
<UIButton: 0x4b95c10; frame = (246 26; 30 30); opaque = NO; tag = 104; layer = <CALayer: 0x4b95be0>>
그런 다음 버튼의 속성을 변경하려면 발신자에게 알려주는 배경 이미지를 말하십시오.
[sender setBackgroundImage:[UIImage imageNamed:@"new-image.png"] forState:UIControlStateNormal];
태그가 필요한 경우 Acburk의 방법은 정상입니다.
// how do I know which button sent this message?
// processing button press for this row requires an indexPath.
실제로 매우 간단합니다 :
- (void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
CGPoint rowButtonCenterInTableView = [[rowButton superview] convertPoint:rowButton.center toView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:rowButtonCenterInTableView];
MyTableViewItem *rowItem = [self.itemsArray objectAtIndex:indexPath.row];
// Now you're good to go.. do what the intention of the button is, but with
// the context of the "row item" that the button belongs to
[self performFooWithItem:rowItem];
}
나를 위해 잘 일 : p
대상 활동 설정을 조정하려면 메소드에 이벤트 매개 변수를 포함시킨 다음 해당 이벤트의 터치를 사용하여 터치의 좌표를 해결할 수 있습니다. 좌표는 여전히 터치 뷰 바운드에서 해결해야하지만 일부 사람들에게는 더 쉬운 것처럼 보일 수 있습니다.
nsmutable 배열을 만들고 해당 배열에 모든 버튼을 넣으십시오 [array addobject : yourbutton];
버튼 프레스 메소드에서
-
(void)buttonPressedAction:(id)sender
{
UIButton *button = (UIButton *)sender;
for(int i=0;i<[yourArray count];i++){
if([buton isEqual:[yourArray objectAtIndex:i]]){
//here write wat u need to do
}
}
버튼이 테이블 바닥 글에있을 때 코코넛에 대한 약간의 변형 (이것을 해결하는 데 도움이되었습니다).
-(IBAction) buttonAction:(id)sender;
{
id parent1 = [sender superview]; // UiTableViewCellContentView
id parent2 = [parent1 superview]; // custom cell containing the content view
id parent3 = [parent2 superview]; // UITableView containing the cell
id parent4 = [parent3 superview]; // UIView containing the table
UIView *myContentView = (UIView *)parent1;
UITableViewCell *myTableCell = (UITableViewCell *)parent2;
UITableView *myTable = (UITableView *)parent3;
UIView *mainView = (UIView *)parent4;
CGRect footerViewRect = myTableCell.frame;
CGRect rect3 = [myTable convertRect:footerViewRect toView:mainView];
[cc doSomethingOnScreenAtY:rect3.origin.y];
}
나는 항상 태그를 사용합니다.
서브 클래스가 필요합니다 UITableviewCell
버튼 누름을 처리하십시오.
간단 해; 사용자 정의 셀을 만들고 버튼 출구를 가져옵니다.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = @"identifier";
customCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.yourButton.tag = indexPath.Row;
- (void)buttonPressedAction:(id)sender
위의 메소드에서 ID를 변경하십시오 (UIButton *)
sender.tag를 수행하여 어떤 버튼을 탭하는지 값을 얻을 수 있습니다.
서브 클래스 버튼을 사용하여 필요한 값을 저장하고 프로토콜 (ControlWithData 또는 무언가)을 생성 할 수 있습니다. 테이블 뷰 셀에 버튼을 추가 할 때 값을 설정하십시오. 터치 업 이벤트에서 발신자가 프로토콜을 준수하고 데이터를 추출하는지 확인하십시오. 일반적으로 테이블 뷰 셀에 렌더링되는 실제 객체에 대한 참조를 저장합니다.
Swift 2 업데이트
다음은 해당 버튼의 다른 ViewController로 데이터를 보내었던 버튼을 찾는 방법입니다. indexPath.row
내가 가정한다고 가정 하듯이 대부분의 요점이라고 생각합니다!
@IBAction func yourButton(sender: AnyObject) {
var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(position)
let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as
UITableViewCell
print(indexPath?.row)
print("Tap tap tap tap")
}
ViewController 클래스를 사용하고 TableView를 추가 한 사람들의 경우 TableViewController 대신 ViewController를 사용하여 액세스하기 위해 TableView를 수동으로 추가했습니다.
다음은 해당 버튼을 누르고 전달할 때 데이터를 다른 VC로 전달하는 코드입니다. 셀 indexPath.row
@IBAction func moreInfo(sender: AnyObject) {
let yourOtherVC = self.storyboard!.instantiateViewControllerWithIdentifier("yourOtherVC") as! YourOtherVCVIewController
var position: CGPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(position)
let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath!)! as
UITableViewCell
print(indexPath?.row)
print("Button tapped")
yourOtherVC.yourVarName = [self.otherVCVariable[indexPath!.row]]
self.presentViewController(yourNewVC, animated: true, completion: nil)
}
여기서 나는 커스텀 셀을 사용하고 있습니다.이 코드는 완벽하게 작동합니다.
@IBAction func call(sender: UIButton)
{
var contentView = sender.superview;
var cell = contentView?.superview as EmployeeListCustomCell
if (!(cell.isKindOfClass(EmployeeListCustomCell)))
{
cell = (contentView?.superview)?.superview as EmployeeListCustomCell
}
let phone = cell.lblDescriptionText.text!
//let phone = detailObject!.mobile!
let url:NSURL = NSURL(string:"tel://"+phone)!;
UIApplication.sharedApplication().openURL(url);
}
Chris Schwerdt의 솔루션이지만 Swift에서 저를 위해 일했습니다.
@IBAction func rateButtonTapped(sender: UIButton) {
let buttonPosition : CGPoint = sender.convertPoint(CGPointZero, toView: self.ratingTableView)
let indexPath : NSIndexPath = self.ratingTableView.indexPathForRowAtPoint(buttonPosition)!
print(sender.tag)
print(indexPath.row)
}
이 문제는 두 부분으로 구성됩니다.
1) 인덱스 경로 얻기 UITableViewCell
프레스가 포함된 UIButton
다음과 같은 몇 가지 제안이 있습니다.
업데이트 중
UIButton
'에스tag
~에cellForRowAtIndexPath:
인덱스 경로를 사용하는 방법row
값.이는 업데이트가 필요하므로 좋은 해결책이 아닙니다.tag
계속해서 두 개 이상의 섹션이 있는 테이블 보기에서는 작동하지 않습니다.추가
NSIndexPath
속성을 사용자 정의 셀에 추가하고 대신 업데이트합니다.UIButton
'에스tag
~에cellForRowAtIndexPath:
방법.이렇게 하면 여러 섹션 문제가 해결되지만 항상 업데이트가 필요하므로 여전히 좋지 않습니다.부모에 대한 약한 참조 유지
UITableView
사용자 정의 셀을 생성하고 사용하는 동안indexPathForCell:
인덱스 경로를 가져오는 방법입니다.조금 나아진 것 같습니다. 아무것도 업데이트할 필요가 없습니다.cellForRowAtIndexPath:
방법이지만 사용자 정의 셀을 생성할 때 여전히 약한 참조를 설정해야 합니다.셀을 사용하여
superView
부모에 대한 참조를 얻는 속성UITableView
.사용자 정의 셀에 속성을 추가할 필요가 없으며 생성 시/나중에 아무것도 설정/업데이트할 필요가 없습니다.하지만 세포의superView
iOS 구현 세부 사항에 따라 다릅니다.따라서 직접 사용할 수는 없습니다.
그러나 이는 문제의 셀이 UITableView에 있어야 하므로 간단한 루프를 사용하여 달성할 수 있습니다.
UIView* view = self;
while (view && ![view isKindOfClass:UITableView.class])
view = view.superview;
UITableView* parentTableView = (UITableView*)view;
따라서 이러한 제안은 인덱스 경로를 얻기 위한 간단하고 안전한 사용자 정의 셀 메서드로 결합될 수 있습니다.
- (NSIndexPath *)indexPath
{
UIView* view = self;
while (view && ![view isKindOfClass:UITableView.class])
view = view.superview;
return [(UITableView*)view indexPathForCell:self];
}
이제부터 이 방법을 사용하여 다음을 탐지할 수 있습니다. UIButton
눌려있습니다.
2) 버튼 누름 이벤트를 상대방에게 알리기
내부적으로 어느 쪽인지 파악한 후 UIButton
정확한 인덱스 경로가 있는 사용자 정의 셀을 누르면 이 정보를 다른 당사자(대부분 UITableView
).따라서 이 버튼 클릭 이벤트는 유사한 추상화 및 논리 수준에서 처리될 수 있습니다. didSelectRowAtIndexPath:
UITableView 대리자의 메서드입니다.
이를 위해 두 가지 접근 방식을 사용할 수 있습니다.
a) 위임: 사용자 정의 셀은 delegate
속성을 가지며 프로토콜을 정의할 수 있습니다.버튼을 누르면 해당 위임 메서드만 수행됩니다. delegate
재산.하지만 이것은 delegate
속성은 생성될 때 각 사용자 정의 셀에 대해 설정되어야 합니다.대안으로 사용자 정의 셀은 상위 테이블 뷰에서 위임 메서드를 수행하도록 선택할 수 있습니다. delegate
도.
b) 알림 센터: 사용자 정의 셀은 사용자 정의 알림 이름을 정의하고 이 알림을 인덱스 경로 및 상위 테이블 보기 정보와 함께 게시할 수 있습니다. userInfo
물체.각 셀에 대해 아무것도 설정할 필요가 없으며 사용자 정의 셀 알림에 대한 관찰자를 추가하는 것만으로도 충분합니다.
나는 서브 클래스 솔루션을 사용합니다 UIButton
그리고 나는 여기에서 그것을 공유해야한다고 생각했다.
class ButtonWithIndexPath : UIButton {
var indexPath:IndexPath?
}
그런 다음 IndexPath를 업데이트하는 것을 잊지 마십시오 cellForRow(at:)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let returnCell = tableView.dequeueReusableCell(withIdentifier: "cellWithButton", for: indexPath) as! cellWithButton
...
returnCell.button.indexPath = IndexPath
returnCell.button.addTarget(self, action:#selector(cellButtonPressed(_:)), for: .touchUpInside)
return returnCell
}
따라서 버튼의 이벤트에 응답 할 때는 다음과 같이 사용할 수 있습니다.
func cellButtonPressed(_ sender:UIButton) {
if sender is ButtonWithIndexPath {
let button = sender as! ButtonWithIndexPath
print(button.indexPath)
}
}