Bir UITableView'da hangi UIButton'a basıldığını algılama


212

Bir var UITableView5 ile UITableViewCells. Her hücre UIButtonaşağıdaki gibi kurulmuş bir hücre içerir :

- (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;
}

Sorum şu: buttonPressedAction:yöntemde, hangi düğmeye basıldığını nasıl bilebilirim? Etiketleri kullanmayı düşündüm ama bunun en iyi yol olduğundan emin değilim. indexPathKontrole bir şekilde etiketlemek istiyorum .

- (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. 
}

Bunu yapmanın standart yolu nedir?

Düzenle:

Bunu aşağıdakileri yaparak çözdüm. Hala bunu yapmanın standart yolu mu yoksa daha iyi bir yolu mu var?

- (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;
}

Unutulmaması gereken şey, hücrenin oluşturulmasında etiketi ayarlayamadığım için hücre yerine ayıklanabileceğidir. Çok kirli. Daha iyi bir yol olmalı.


Etiket çözümünüzü kullanırken herhangi bir sorun görmüyorum. Hücreler yeniden kullanılır, bu nedenle etiketi burada yaptığınız gibi satır dizinine ayarlamak mantıklıdır. Bunu, aşağıda önerildiği gibi, dokunma konumunu bir satır dizinine dönüştürmekten çok daha zarif bir çözüm olarak görüyorum.
Erik van der Neut

Yanıtlar:


400

Apple'ın Aksesuar örneğinde aşağıdaki yöntem kullanılır:

[button addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

Daha sonra dokunmatik işleyicide alınan dokunmatik koordinat ve dizin yolu bu koordinattan hesaplanır:

- (void)checkButtonTapped:(id)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    if (indexPath != nil)
    {
     ...
    }
}

Evet, yerleştiğim şey bu (düzenlememe bakın). Size uygun olmadığını kabul ediyorum.
dizgin

2
Ancak UIButton'u UITableViewCell'e kendiniz eklersiniz, böylece hücre oluştururken yaptığınız şeyle tutarlı olmanız gerekir. Bu yaklaşım gerçekten zarif görünmese de itiraf etmeliyim
Vladimir

1
İlk çözüm için, ilk denetim çağrısı size contentView'i ve son olarak ikincisi size UITableViewCell'i vereceğinden [[düğme denetimi] denetimi] almanız gerekir. İkinci çözüm, satır dizinini geçersiz kılacağından hücreleri ekler / kaldırırsanız iyi çalışmaz. Bu nedenle, belirtildiği gibi ilk çözüm ile gittim ve mükemmel çalıştı.
baskın

3
Bu, düğmenin sahibi olan hücreyi güvenilir bir şekilde seçecektir: UIView * view = button; while (! [view isKindOfClass: [UITableViewCell class]])) {view = [görüntüleme denetimi]}
Jacob Lyles

1
Kullanırken bir tuzak var: [button addTarget: self action: @selector (checkButtonTapped :) forControlEvents: UIControlEventTouchUpInside]; addTarget: action: forControlEvents: tabloyu kaydırdığınızda birden çok çoğaltılmış hedef ve eylem ekleyeceğinden, önceki hedefleri ve eylemleri kaldırmaz, bu nedenle checkButtonTapped: yöntemi düğmeyi tıkladığınızda birçok kez çağrılır. Hedefi ve eylemi eklemeden önce kaldırmanız daha iyi olur
bandw

48

Hücrenin indexPath bir başvuru elde etmek için denetimin denetimini kullanma yöntemi buldum mükemmel çalıştı. İpucu bağlantı metni için iphonedevbook.com (macnsmith) sayesinde

-(void)buttonPressed:(id)sender {
 UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
 NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...

}

Cocoanut, kod parçan bu sorundaki kendi varyasyonum için beni doğru yöne çekti. Teşekkürler! Başka birinin ihtiyacı olması durumunda, özel durumum, düğmenin altbilginin bir parçası olarak görüntülenen özel bir hücrede olmasıydı. Aşağıdaki kodu ekleyeceğim
yazılım

Siz (Stackoverflow okuyucu) bunu denerseniz ve sizin için çalışmazsa, uygulamanızda UIButton'unuzun aslında UITableViewCell'inizin torunu olup olmadığını kontrol edin. Benim uygulamada, benim UIButton benim UITableViewCell doğrudan bir çocuktu, bu yüzden Cocoanut kodunda "gözetlemek" birini almak gerekiyordu, ve sonra çalıştı.
Jon Schneider

29
Bu çok, çok yanlış ve işletim sisteminin yeni sürümlerinde bozuldu. Sahip olmadığınız süpervizör ağaçları yürümeyin.
Kenrik Mart

2
Bu benim için iOS 6 altında çalışıyordu, ancak iOS 7'de bozuldu. @KenrikMarch'ın geçerli bir noktası var gibi görünüyor!
Jon Schneider

3
iOS 7'de denetimde bir adım daha var. örneğin [[[gönderenin denetimi] denetimi] superView];
CW0007007

43

İşte böyle yapıyorum. Basit ve özlü:

- (IBAction)buttonTappedAction:(id)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero
                                           toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    ...
}

2
Daha da basit: ;-) CGPointZeroyerine kullanınCGPointMake(0, 0)
Jakob W

Onunla çalışmak kolay. Ayrıca, Swift 3'e çevirmek kolay. Sen en
Francisco Romero

Bunu aşağıda Swift'e çevirdi. Bulabildiğim en kolay çözüm. Teşekkürler Chris!
Rutger Huijsmans

6

Bu soruna başka bir yerde güzel bir çözüm buldum, düğmedeki etiketlerle uğraşmak yok:

- (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...
}

5
Bu olayda 'event' nesnesini nereden alacağınız açık değil.
Nick Ludlam

Bu benim gittiğim çözüm. Dizinleri değiştiği için satır eklerken / kaldırırken etiketleri kullanmak öngörülemez. Ayrıca,
baskın

@ NickLudlam: muhtemelen yöntem adı buttonPressedAction:değil buttonPressedAction:forEvent:.
KPM

5

Nasıl gibi bilgileri gönderme hakkında NSIndexPathiçinde UIButtonkullanarak çalışma zamanı enjeksiyon.

1) İçe aktarma işleminde çalışma süresine ihtiyacınız var

2) statik sabit ekleyin

3) NSIndexPathkullanarak zamanında çalışma düğmesine ekleyin :

(void) setMetaData: (id) hedef ileObject: (id) newObj

4) düğmesine basın kullanarak meta veri almak:

(İd) metaData: (id) hedef

Zevk almak

    #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
    }

1
Tablo yeniden düzenlenirse veya bir satır silinirse, bu çalışmaz.
Neil

5

(@Vladimir) 'in cevabı Swift:

var buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView)
var indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!

Her ne kadar kontrol etmek indexPath != nilbana parmak verir ... "NSIndexPath NSString bir alt türü değil"


5

Swift 4.2 ve iOS 12 ile sorununuzu çözmek için aşağıdaki 5 örnekten birini seçebilirsiniz .


# 1. Kullanılması UIView'ın convert(_:to:)ve UITableView' lerindexPathForRow(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. Kullanma UIViewsitesindeki convert(_:to:)ve UITableView'nin indexPathForRow(at:)(alternatif)

Bu, niliçindeki targetparametreye ilettiğimiz önceki örneğe bir alternatiftir addTarget(_:action:for:). Bu şekilde, ilk yanıtlayıcı eylemi uygulamazsa, uygun bir uygulama bulunana kadar yanıtlayıcı zincirindeki bir sonraki yanıtlayıcıya gönderilir.

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)
    }

}

3.. Kullanılması UITableView's indexPath(for:)ve temsilci desen

Bu örnekte, görünüm denetleyicisini hücrenin temsilcisi olarak ayarladık. Hücrenin düğmesine basıldığında, uygun temsilci yöntemine bir çağrı tetikler.

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.. Kullanılması UITableView's indexPath(for:)ve heyeti için bir kapatma

Bu, düğme dokunuşunu işlemek için protokol-temsilci bildirimi yerine bir kapatma kullandığımız önceki örneğe bir alternatiftir.

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.. Kullanılması UITableViewCell'ın accessoryTypeve UITableViewDelegate' lertableView(_:accessoryButtonTappedForRowWith:)

Düğmeniz bir UITableViewCellstandart aksesuar kontrolü ise, herhangi bir dokunma UITableViewDelegate's çağrısını tetikleyerek tableView(_:accessoryButtonTappedForRowWith:)ilgili dizin yolunu almanızı sağlar.

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)
    }

}

5
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")
    }

3

Söylediğin gibi tag özelliği, etiketi böyle ayarlamak istiyorsunuz:

[button setTag:indexPath.row];

ardından etiketi buttonPressedAction'ın içine şu şekilde alırsınız:

((UIButton *)sender).tag

Veya

UIButton *button = (UIButton *)sender; 
button.tag;

5
Bu yaklaşım bölümlü tablolar için tamamen kırılmıştır.
ohhorob

Hayır, bölümü etikete koymak için basit bir işlev kullanabilirsiniz.
ACBurk

2
tagbir tamsayıdır. dizin yollarını görünüm etiketlerine kodlama / kod çözme konusunda biraz beceriksiz görünüyor.
ohhorob

Bu doğru, ama bir çözüm olsa da, bölümlerim varsa kullanacağım bir çözüm değil. Söylemeye çalıştığım tek şey, bu yöntem kullanılarak yapılabileceği, kırılmadığıydı. Daha iyi, daha karmaşık bir sürüm, dizin yolunu UITableView içindeki düğmenin konumundan belirler. Bununla birlikte, dizgin yalnızca beş hücresi olduğunu (bölümler olmadan) söylediğinden, muhtemelen bu yöntemi karmaşık hale getirir ve ilk yorumunuz ve tüm yorum dizisi anlamsızdır.
ACBurk

3

Etiket yolunu sevmeme rağmen ... etiketleri herhangi bir nedenle kullanmak istemiyorsanız NSArray, önceden hazırlanmış düğmelerin bir üyesini oluşturabilirsiniz :

NSArray* buttons ;

ardından tableView öğesini oluşturmadan önce bu düğmeleri oluşturun ve diziye itin.

Sonra tableView:cellForRowAtIndexPath:fonksiyonun içinde şunları yapabilirsiniz:

UIButton* button = [buttons objectAtIndex:[indexPath row] ] ;
[cell.contentView addSubview:button];

Sonra buttonPressedAction:fonksiyonda,

- (void)buttonPressedAction:(id)sender {
   UIButton* button = (UIButton*)sender ;
   int row = [buttons indexOfObject:button] ;
   // Do magic
}

2

KISIMLARI KULLANMAK - NSIndexPath'i özel bir UITableViewCell'de sakladım

IN CLKIndexPricesHEADERTableViewCell.xib

IN IB XIB'e UIButton ekleyin - DONT eylem ekleyin!

Outlet @property (koru, anatomik olmayan) ekleyin IBOutlet UIButton * buttonIndexSectionClose;

IB'de bir eylemi CTRL + DRAG ETMEYİN (aşağıdaki kodda yapılır)

@interface CLKIndexPricesHEADERTableViewCell : UITableViewCell
...
@property (retain, nonatomic) IBOutlet UIButton *buttonIndexSectionClose;
@property (nonatomic, retain) NSIndexPath * indexPathForCell;
@end

ViewForHeaderInSection içinde (tablonuzda yalnızca 1 bölüm varsa cellForRow .... etc için de çalışmalıdır)

- 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];

... hücreniz için veri almak için bölümü kullanın

... doldurun

   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;
}

USER, Bölüm başlığında SİL düğmesine basar ve bu çağrı

- (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__);
    }
}

Bu örnekte bir Sil düğmesi ekledim, bu yüzden onaylamak için UIAlertView göstermelisiniz

Bölümü saklıyorum ve VC bir ivar bölüm hakkında bilgi depolamak sözlüğü saklamak

- (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);
    }
}

2
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; //:)
}

Eğer deleteRowsAtIndexPaths çağırırsanız, bir hücrenin indexPath değişebilir, çünkü bu biraz hatalı.
John Gibb

deleteRowsAtIndexPaths, cellForRowAtIndexPath öğesinin yeniden çağrılmasına neden olur. Daha sonra düğmeler yeni doğru indexPath'lere sahip olacaktır.
mmmanishs

1

Benim için de çalışıyor, teşekkürler @Cocoanut

Hücrenin indexPath bir başvuru elde etmek için denetimin denetimini kullanma yöntemi buldum mükemmel çalıştı. İpucu bağlantı metni için iphonedevbook.com (macnsmith) sayesinde

-(void)buttonPressed:(id)sender {
 UITableViewCell *clickedCell = (UITableViewCell *)[[sender superview] superview];
 NSIndexPath *clickedButtonPath = [self.tableView indexPathForCell:clickedCell];
...

}

0

etiket desenini kullanabilirsiniz:

- (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)
}

Tek bir hücrede birden çok denetimim olsaydı denetimleri nasıl etiketleyebilirim?
dizgin

Bunun işe yarayacağından emin değilim - eğer hücre satır # 1 için oluşturulursa, o zaman etiket 1'i alır. # 3 satırı için ayıklanırsa, yine de 3 değil, 1 etiketi olacaktır.
dizgin

sanırım ikinci yorum konusunda haklısın. benim hatam. Bence en iyi çözüm, UIButton'u alt sınıflara ayırmak, başka bir mülk veya iki tane kendiniz eklemek ve daha sonra bunları uygun durumlarda ayarlamak / almak (kodunuzda bulunan 1 etiketiyle sopa)
Nir Levy

0

Bir şey mi kaçırıyorum? Sadece düğmeyi tanımlamak için göndereni kullanamazsınız. Gönderen size şöyle bilgi verecektir:

<UIButton: 0x4b95c10; frame = (246 26; 30 30); opaque = NO; tag = 104; layer = <CALayer: 0x4b95be0>>

Düğmenin özelliklerini değiştirmek istiyorsanız, gönderene söylediğiniz arka plan resmini söyleyin:

[sender setBackgroundImage:[UIImage imageNamed:@"new-image.png"] forState:UIControlStateNormal];

Etikete ihtiyacınız varsa ACBurk'un yöntemi iyidir.


1
Düğmenin ilgili olduğu "nesnelerini" arıyorlar
ohhorob

0
// how do I know which button sent this message?
// processing button press for this row requires an indexPath.

Aslında oldukça basit:

- (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];
}

Benim için iyi çalışıyor: P

hedef eylem kurulumunuzu ayarlamak istiyorsanız, olay parametresini yönteme dahil edebilir ve ardından dokunmanın koordinatlarını çözmek için o olayın dokunuşlarını kullanabilirsiniz. Dokunmatik görünüm sınırlarında koordinatların hala çözülmesi gerekiyor, ancak bu bazı insanlar için daha kolay görünebilir.


0

nsmutable bir dizi oluşturun ve tüm düğmeyi o diziye usint [array addObject: yourButton] koyun;

düğme basın yönteminde

-

 (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

}
}

0

Düğme bir tablonun altbilgisindeyken (tıklanan hücreyi bulmanızı engelleyen) Cocoanuts yanıtında (bunu çözmeme yardımcı olan) küçük bir varyasyon:

-(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];
}

0

Her zaman etiket kullanırım.

UITableviewCellDüğmeye basmayı alt sınıfta tutmanız ve oradan basmanız gerekir.


Nasıl olduğunu tam olarak anlamıyorum. Tag özelliği, hücre oluşturulurken ayarlanır - bu hücre, aynı tanımlayıcıya sahip her satır için yeniden kullanılabilir. Bu etiket, yeniden kullanılabilir genel bir hücredeki denetime özgüdür. Bu etiketi, genel bir şekilde oluşturulan hücrelerdeki düğmeleri farklılaştırmak için nasıl kullanabilirim? Biraz kod gönderebilir misiniz?
dizgin

0

Basit; özel bir hücre yapın ve düğmenin çıkışını alın

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
         NSString *identifier = @"identifier";
        customCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    cell.yourButton.tag = indexPath.Row;

- (void)buttonPressedAction:(id)sender

yukarıdaki yöntemde kimliği değiştir (UIButton *)

Sender.tag komutunu kullanarak hangi düğmeye dokunulduğunu görebilirsiniz.


0

Gerekli değeri saklamak için düğmeyi alt sınıflayın, belki bir protokol oluşturun (ControlWithData veya başka bir şey). Düğmeyi tablo görünümü hücresine eklediğinizde değeri ayarlayın. Rötuş etkinliğinizde, gönderenin protokole uyup uymadığına bakın ve verileri çıkarın. Normalde tablo görünümü hücresinde işlenen gerçek nesneye bir başvuru depolar.


0

SWIFT 2 GÜNCELLEME

İşte hangi düğmenin dokunduğunu bulmak için + başka bir ViewController'a veri göndermek için bu düğmenin en indexPath.rowönemlisi olduğunu varsayıyorum!

@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")

    }

Bir ViewController sınıfı kullanan ve bir tableView ekleyenler için, bir TableViewController yerine bir ViewController kullanıyorum, bu yüzden erişmek için el ile tableView ekledi.

İşte o düğmeye dokunarak zaman başka VC veri geçirildiği ve kodudur Hücrenin 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)

}

0

Burada özel kod kullanıyorum unutmayın bu kod mükemmel benim için çalışıyor

 @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);
    }

0

Chris Schwerdt'ın çözümü ama sonra Swift'te benim için çalıştı:

@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)
}

0

Bu sorunun iki bölümü vardır:

1) UITableViewCellBasılan dizin yolunu almaUIButton

Bazı öneriler var:

  • Güncelleniyor UIButton's tagin cellForRowAtIndexPath:endeks yolun kullanarak yöntemle rowdeğerini. Bu, tagsürekli güncellenmeyi gerektirdiği ve birden fazla bölüm içeren tablo görünümleriyle çalışmadığı için iyi bir çözüm değildir.

  • Bir ekleme NSIndexPathözel hücreye mülkiyet ve yerine bu güncelleme UIButtons' tagin cellForRowAtIndexPath:yöntemiyle. Bu, çoklu bölüm sorununu çözer, ancak her zaman güncellenmesini gerektirdiği için hala iyi değildir.

  • Oluştururken ve dizin yolunu almak için yöntemi UITableViewkullanarak özel hücrede üst öğeye zayıf bir referans tutmak indexPathForCell:. Biraz daha iyi görünüyor, cellForRowAtIndexPath:yöntemdeki herhangi bir şeyi güncellemeye gerek yok , ancak özel hücre oluşturulduğunda yine de zayıf bir referans ayarlamayı gerektiriyor.

  • superViewÜst öğeye başvuru almak için hücrenin özelliğini kullanma UITableView. Özel hücreye herhangi bir özellik eklemenize ve oluşturma / daha sonra herhangi bir şey ayarlamanıza / güncellemenize gerek yoktur. Ancak hücre superView, iOS uygulama ayrıntılarına bağlıdır. Böylece doğrudan kullanılamaz.

Ancak, söz konusu hücrenin UITableView'da olması gerektiğinden emin olduğumuzdan, bu basit bir döngü kullanılarak gerçekleştirilebilir:

UIView* view = self;
while (view && ![view isKindOfClass:UITableView.class])
    view = view.superview;
UITableView* parentTableView = (UITableView*)view;

Bu nedenle, bu öneriler dizin yolunu almak için basit ve güvenli bir özel hücre yönteminde birleştirilebilir:

- (NSIndexPath *)indexPath
{
    UIView* view = self;

    while (view && ![view isKindOfClass:UITableView.class])
        view = view.superview;

    return [(UITableView*)view indexPathForCell:self];
}

Şu andan itibaren, bu yöntem hangisini tespit etmek için kullanılabilir UIButton basılacağını .

2) Düğme basın olayı hakkında diğer tarafları bilgilendirmek

Dahili UIButtonolarak hangi indeks yolu ile hangi özel hücrenin basıldığını bildikten sonra , bu bilgilerin diğer taraflara gönderilmesi gerekir (büyük olasılıkla UITableView. Bu nedenle, bu düğme tıklama olayı didSelectRowAtIndexPath:, UITableView temsilcisinin yöntemine benzer bir soyutlama ve mantık düzeyinde işlenebilir .

Bunun için iki yaklaşım kullanılabilir:

a) Temsilci seçme: özel hücre bir delegateözelliğe sahip olabilir ve bir protokol tanımlayabilir. Düğmeye basıldığında, delegateözelliği üzerinde temsilci yöntemler uygular . Ancak bu delegateözelliğin, oluşturulduklarında her özel hücre için ayarlanması gerekir. Alternatif olarak, özel hücre, temsilci yöntemlerini üst tablo görünümünde gerçekleştirmeyi seçebilirdelegate de .

b) Bildirim Merkezi: özel hücreler özel bir bildirim adı tanımlayabilir ve bu bildirimi userInfonesnede sağlanan dizin yolu ve üst tablo görünümü bilgileriyle gönderebilir . Her hücre için herhangi bir şey ayarlamaya gerek yoktur, sadece özel hücrenin bildirimi için bir gözlemci eklemek yeterlidir.


0

Ben alt sınıf bir çözüm kullanın UIButtonve ben sadece burada paylaşmak gerektiğini düşündüm, Swift kodları:

class ButtonWithIndexPath : UIButton {
    var indexPath:IndexPath?
}

Ardından dizinini güncellemeyi unutmayın 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
}

Düğmenin etkinliğine yanıt verirken,

func cellButtonPressed(_ sender:UIButton) {
    if sender is ButtonWithIndexPath {
        let button = sender as! ButtonWithIndexPath
        print(button.indexPath)
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.