UITableViewCell içinde düğmeyi tıklayın


140

Bir tablo görünümü ve tablo hücre şablonu için ayrı bir uç ile bir görünüm denetleyicisi var. Hücre şablonunda bazı düğmeler bulunur. Tablo görünümünü tanımladığım görünüm denetleyicisinin içinde tıklatılan hücrenin diziniyle birlikte düğme tıklatmasına erişmek istiyorum.

Ben Yani ViewController.hve ViewController.mben nerede UITableViewve TableTemplate.h, TableTemplate.mve TableTemplate.xibben nerede ucu tanımladı. Hücre dizini ile düğme tıklama olayı istiyorum ViewController.m.

Bunu nasıl yapabileceğim konusunda herhangi bir yardım?

Yanıtlar:


258

1) cellForRowAtIndexPath:Yönteminizde, düğme etiketini dizin olarak atayın:

cell.yourbutton.tag = indexPath.row;

2) Düğmeniz için aşağıdaki gibi hedef ve eylem ekleyin:

[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

3) Aşağıdaki gibi indekse dayalı eylemleri kodlayın ViewControler:

-(void)yourButtonClicked:(UIButton*)sender
{
     if (sender.tag == 0) 
     {
         // Your code here
     }
}

Birden çok Bölüm için güncellemeler:

Birden çok satır ve bölüm için tablo görünümünde düğme tıklamasını algılamak için bu bağlantıyı kontrol edebilirsiniz .


1
Bu, ikinci adımda Arayüz Oluşturucu (IB) ile de yapılabilir. Düğme etiketinizin ayarlandığından emin olun. Gerçekten eylem çağrınızı karıştırmak istemiyorsunuz. Ya IB yoluyla yapın ya da kodunuzda açıkça yapın.
Sententia

@Mani MVC kırmaz - eylem Hücre değil TableView.
davecom

@davecom Düğme hedefini hücre (IB aracılığıyla) olarak ayarlarsanız, tableView'dan nasıl tetiklenir? Veya düğme hedef hücrenin xib yerleştirilen tablo görünümüne bağlamak için herhangi bir yolu var mı?
Mani

24
Bu çözüm, satır eklemeye ve silmeye başladığınızda sorunla karşılaşır. Satırlar kaydırıldığında etiket güncellenmez. Satıra bir referans tutmak yerine. Benzersiz bir nesne kimliğine referans tutmak daha iyi olabilir.
Vincent Cheong

1
Kendinizi görünümlerin etiket özelliklerine değer atarken bulduğunuzda, daha sonra sizi ısırabilecek çok kötü bir kod kokunuz vardır. Bulduğunuz ilk SO yayını değil, hedefinize ulaşmak için daha iyi yollar arayın.
TigerCoding

148

Delegeler gidilecek yol.

Diğer yanıtlarda görüldüğü gibi, görünümleri kullanarak modası geçmiş olabilir. Yarın kim bilir başka bir sargı olabilir ve kullanması gerekebilir cell superview]superview]superview]superview]. Etiketleri kullanırsanız, hücreyi tanımlamak için başka koşul varsa n sayısıyla sonuçlanırsınız. Tüm bu delegeleri kurmaktan kaçınmak için. (Bunu yaparak, yeniden kullanılabilir bir hücre sınıfı oluşturacaksınız. Temel sınıfla aynı hücre sınıfını kullanabilirsiniz ve tek yapmanız gereken temsilci yöntemlerini uygulamaktır.)

Öncelikle, düğme tıklamaları iletişim kurmak için (temsilci) hücre tarafından kullanılacak bir arayüze (protokole) ihtiyacımız var. ( Protokol için ayrı bir .h dosyası oluşturabilir ve hem tablo görünümü denetleyicisine hem de özel hücre sınıflarına dahil edebilirsiniz VEYA dosyayı yine de tablo görünümü denetleyicisine dahil edilecek özel hücre sınıfına ekleyebilirsiniz )

@protocol CellDelegate <NSObject>
- (void)didClickOnCellAtIndex:(NSInteger)cellIndex withData:(id)data;
@end

Bu protokolü özel hücre ve tablo görünümü denetleyicisine ekle. Tablo görünümü denetleyicisinin bu protokolü onayladığından emin olun.

Özel hücrede iki özellik oluşturun:

@property (weak, nonatomic) id<CellDelegate>delegate;
@property (assign, nonatomic) NSInteger cellIndex;

In UIButtonIBAction temsilci tıklama: ( aynı görüntü denetleyicisi geri devredilen gereken özel hücre sınıfında herhangi bir işlem için yapılabilir )

- (IBAction)buttonClicked:(UIButton *)sender {
    if (self.delegate && [self.delegate respondsToSelector:@selector(didClickOnCellAtIndex:withData:)]) {
        [self.delegate didClickOnCellAtIndex:_cellIndex withData:@"any other cell data/property"];
    }
}

cellForRowAtIndexPathHücreyi ayıkladıktan sonra tablo görünümü denetleyicisinde , yukarıdaki özellikleri ayarlayın.

cell.delegate = self;
cell.cellIndex = indexPath.row; // Set indexpath if its a grouped table.

Temsilciyi tablo görünümü denetleyicisine uygulayın:

- (void)didClickOnCellAtIndex:(NSInteger)cellIndex withData:(id)data
{
    // Do additional actions as required.
    NSLog(@"Cell at Index: %d clicked.\n Data received : %@", cellIndex, data);
}

Bu, tablo görünümü denetleyicisinde özel hücre düğmesi eylemleri almak için ideal bir yaklaşım olacaktır.


2
Temsilciyi neden hücrenin güçlü bir özelliği haline getirdiniz? Bu, kontrolörün hücreyi zayıf bir şekilde tuttuğunu bilmediğiniz sürece size bir tutma döngüsü verecektir.
JulianSymes

hücre silindikten sonra güncellenen _cellIndex beign'a ne dersiniz?
skornos

2
Bir arkadaşımdan her hücrede delege kullanmanın bellek tüketimine neden olduğunu söylediğini duydum, bu yüzden etiketleri kullanın. Bu doğru mu?
Bista


@the_UB Bir etiket ayarlamak ve tek bir referans depolamak arasında fazla bir şey olamaz. Muhtemelen bir etiket daha fazla bellek kaplar.
Ian Warburton

66

Etiketlerle oynamak yerine farklı bir yaklaşım izledim. UITableViewCell (OptionButtonsCell) alt sınıfım için temsilci yaptı ve bir indexPath var. Storyboard'daki düğmemden @IBAction'ı OptionButtonsCell'e bağladım ve orada ilgilenen herkese doğru indexPath ile delege yöntemi gönderdim. Dizin yolu hücresinde geçerli indexPath ayarladım ve çalışıyor :)

Kodun kendisi için konuşmasına izin verin:

Swift 3 Xcode 8

OptionButtonsTableViewCell.swift

import UIKit
protocol OptionButtonsDelegate{
    func closeFriendsTapped(at index:IndexPath)
}
class OptionButtonsTableViewCell: UITableViewCell {
    var delegate:OptionButtonsDelegate!
    @IBOutlet weak var closeFriendsBtn: UIButton!
    var indexPath:IndexPath!
    @IBAction func closeFriendsAction(_ sender: UIButton) {
        self.delegate?.closeFriendsTapped(at: indexPath)
    }
}

MyTableViewController.swift

class MyTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, OptionButtonsDelegate {...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "optionCell") as! OptionButtonsTableViewCell
    cell.delegate = self
    cell.indexPath = indexPath
    return cell   
}

func closeFriendsTapped(at index: IndexPath) {
     print("button tapped at index:\(index)")
}

Bana yardımcı olabilir, ben bu çizgisinde hata alıyorum: class MyTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, OptionButtonsDelegate // hatası: protokole 'MyTableViewController' Yedek uygunluk 'UITableViewDataSource'
Ulug'bek Ro'zimboyev

UITableViewDataSource'a birden çok kez uymaya çalıştığınız anlaşılıyor. Belki de veri kaynağına zaten
uyduğunuz

1
ve segue gerçekleştirmek ve başka bir görünüm denetleyicisine gitmek için veri aktarımı nasıl yapılır?
Milad Faridnia

2
En iyi ve en temiz çözüm!
appsunited

31

Bu yardımcı olacaktır: -

UITableViewCell* cell = (UITableViewCell*)[sender superview];
NSIndexPath* indexPath = [myTableView indexPathForCell:cell];

İşte gönderen olayı gönderiyor UIButton örneğidir. myTableView , uğraştığınız UITableView örneğidir.

Sadece hücre referansını doğru al ve tüm işler bitti.

Düğmeleri hücrenin contentView öğesinden kaldırmanız ve alt görünüm olarak doğrudan UITableViewCell örneğine eklemeniz gerekebilir.

Veya

Cell.contentView öğesinde farklı UIButtonları için bir etiket adlandırma düzeni formüle edebilirsiniz. Bu etiketi kullanarak daha sonra satır ve bölüm bilgilerini gerektiği gibi öğrenebilirsiniz.


4
[[gönderenin denetimi] denetimi olmalıdır;
pierre23

2
Bu çok basit hücreler için iyidir. Ancak, hücrenizin derin bir görüş ağacı varsa Mani'nin cevabı en iyisidir.
Sententia

3
Şimdi iOS 7'de UITableViewCell * cell = (UITableViewCell *) [[[gönderenin gözetimi] süpervizyon] denetimi]; Teşekkür ederim.
Rajan Maharjan


22

Aşağıdaki kod size yardımcı olabilir.

İçinde UITableViewadlandırılan özel prototip hücre sınıfı ile aldım .UITableViewCellUIViewController

Bende var ViewController.h, ViewController.mve TableViewCell.h,TableViewCell.m

İşte bunun için kod:

ViewController.h

@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>

@property (strong, nonatomic) IBOutlet UITableView *tblView;

@end

ViewController.m

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return (YourNumberOfRows);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *cellIdentifier = @"cell";

    __weak TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    if (indexPath.row==0) {
        [cell setDidTapButtonBlock:^(id sender)
         {
             // Your code here

         }];
    }    
    return cell;
}

Özel hücre sınıfı:

TableViewCell.h

@interface TableViewCell : UITableViewCell

@property (copy, nonatomic) void (^didTapButtonBlock)(id sender);

@property (strong, nonatomic) IBOutlet UILabel *lblTitle;
@property (strong, nonatomic) IBOutlet UIButton *btnAction;

- (void)setDidTapButtonBlock:(void (^)(id sender))didTapButtonBlock;

@end

ve

UITableViewCell.m

@implementation TableViewCell

- (void)awakeFromNib {
    // Initialization code
    [self.btnAction addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside];

}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}
- (void)didTapButton:(id)sender {
    if (self.didTapButtonBlock)
    {
        self.didTapButtonBlock(sender);
    }
}

Not : Burada UIControlsStoryboard'u kullanarak hepsini aldım .

Umarım size yardımcı olur...!!!


Şimdiye kadarki en iyi yol
Daniel Raouf

15

Aşağıdaki tekniği sevmemin nedeni, aynı zamanda tablo bölümünü tanımlamamda bana yardımcı oldu.

Hücre hücresine Düğme EkleForRowAtIndexPath:

 UIButton *selectTaskBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        [selectTaskBtn setFrame:CGRectMake(15, 5, 30, 30.0)];
        [selectTaskBtn setTag:indexPath.section]; //Not required but may find useful if you need only section or row (indexpath.row) as suggested by MR.Tarun 
    [selectTaskBtn addTarget:self action:@selector(addTask:)   forControlEvents:UIControlEventTouchDown];
[cell addsubview: selectTaskBtn];

Etkinlik addTask:

-(void)addTask:(UIButton*)btn
{
    CGPoint buttonPosition = [btn convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPosition];
    if (indexPath != nil)
    {
     int currentIndex = indexPath.row;
     int tableSection = indexPath.section;
    }
}

Bu yardımı umuyoruz.



12

Swift kapaklarını kullanın:

class TheCell: UITableViewCell {

    var tapCallback: (() -> Void)?

    @IBAction func didTap(_ sender: Any) {
        tapCallback?()
    }
}

extension TheController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: TheCell.identifier, for: indexPath) as! TheCell {
            cell.tapCallback = {
                //do stuff
            }
            return cell
    }
}

7

Tarun'un kodu iOS7'de çalışmaz, çünkü UITableViewCell yapısı değişti ve şimdi bunun yerine "UITableViewCellScrollView" alacaktı.

Bu gönderi , iOS 7'de UITableViewCell'i denetleyerek almak, yapıdaki gelecekteki değişikliklerden bağımsız olarak doğru ana görünümü bulmak için bir döngü oluşturan iyi bir çözüme sahiptir. Bir döngü oluşturmak için kaynar:

    UIView *superView = [sender superview];
    UIView *foundSuperView = nil;

    while (nil != superView && nil == foundSuperView) {
        if ([superView isKindOfClass:[UITableViewCell class]]) {
            foundSuperView = superView;
        } else {
            superView = superView.superview;
        }
    }

Bağlantının daha yeniden kullanılabilir bir çözüm için kodu var, ancak bu işe yarayacak.


6

Hızlı 2.2

Bu düğme için hedef eklemeniz gerekir.

myButton.addTarget(self, action: #selector(ClassName.FunctionName(_:), forControlEvents: .TouchUpInside)

İşlevAdı: bağlı // örneğin

Ve elbette, kullandığınızdan beri bu düğmenin etiketini ayarlamanız gerekir.

myButton.tag = indexPath.row

Bu işlemi UITableViewCell alt sınıflaması ile yapabilirsiniz. Arayüz oluşturucuda kullanın, o hücreye bir düğme bırakın, prizden bağlayın ve işte oraya gidin.

Etiketi bağlı işlevde almak için:

func connected(sender: UIButton) {
    let buttonTag = sender.tag
    // Do any additional setup
}

6

Kapatma ile Swift 3

Bir eylem için viewController'ı geri çağırmak için özel bir UITableViewCell'de bir kapatma kullanmak güzel bir çözümdür.

Hücrede:

final class YourCustomCell: UITableViewCell {

    var callbackClosure: (() -> Void)?

    // Configure the cell here
    func configure(object: Object, callbackClosure: (() -> Void)?) {
       self.callbackClosure = callbackClosure
    }


// MARK: - IBAction
extension YourCustomCell {
    @IBAction fileprivate func actionPressed(_ sender: Any) {
        guard let closure = callbackClosure else { return }
        closure()
    }
}

Görünüm Denetçisi: Tableview Temsilcisi

extension YourViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        guard let cell: YourCustomCell = cell as? YourCustomCell else { return }
        cell.configure(object: object, callbackClosure: { [weak self] in
            self?.buttonAction()
        })
     }
 }

fileprivate extension YourViewController {

    func buttonAction() {
        // do your actions here 
    }
}

5

Hücrenin içindeki düğmeyi alt sınıflandırmanın en basit olduğunu düşünüyorum (Swift 3):

class MyCellInfoButton: UIButton {
    var indexPath: IndexPath?
}

Hücre sınıfınızda:

class MyCell: UICollectionViewCell {
    @IBOutlet weak var infoButton: MyCellInfoButton!
   ...
}

Tablo görünümünün veya koleksiyon görünümünün veri kaynağında, hücreyi ayıklarken, düğmeye dizin yolunu verin:

cell.infoButton.indexPath = indexPath

Böylece bu kodu tablo görünümü denetleyicinize koyabilirsiniz:

@IBAction func handleTapOnCellInfoButton(_ sender: MyCellInfoButton) {
        print(sender.indexPath!) // Do whatever you want with the index path!
}

Arayüz Oluşturucunuzda düğmenin sınıfını ayarlamayı ve handleTapOnCellInfoButtonişleve bağlamayı unutmayın !


düzenlendi:

Bağımlılık enjeksiyonu kullanma. Bir kapatma çağrısı ayarlamak için:

class MyCell: UICollectionViewCell {
    var someFunction: (() -> Void)?
    ...
    @IBAction func didTapInfoButton() {
        someFunction?()
    }
}

ve kapanışı toplama görünümü temsilcisinin willDisplay yöntemine enjekte edin:

 func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    (cell as? MyCell)?.someFunction = {
        print(indexPath) // Do something with the indexPath.
    }
}

Kapanış yaklaşımı bunu yaptığım en şık yöntemdir. İyi iş!
Clifton Labrum

5

Benim İçin İşi.

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     UIButton *Btn_Play = (UIButton *)[cell viewWithTag:101];
     [Btn_Play addTarget:self action:@selector(ButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
-(void)ButtonClicked:(UIButton*)sender {
     CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.Tbl_Name];
     NSIndexPath *indexPath = [self.Tbl_Name indexPathForRowAtPoint:buttonPosition];
}

1
// Add action in cell for row at index path -tableView

cell.buttonName.addTarget(self, action: #selector(ViewController.btnAction(_:)), for: .touchUpInside)

// Button Action

  @objc func btnAction(_ sender: AnyObject) {



        var position: CGPoint = sender.convert(.zero, to: self.tableView)


        let indexPath = self.tableView.indexPathForRow(at: position)
        let cell: UITableViewCell = tableView.cellForRow(at: indexPath!)! as
        UITableViewCell




}

1

hızlı 4 için:

inside the cellForItemAt ,
   
cell.chekbx.addTarget(self, action: #selector(methodname), for: .touchUpInside)

then outside of cellForItemAt
@objc func methodname()
{
//your function code
}


1

Parametre değerini kapatmayı kullanarak hücreden UIViewController'a geçirmek istiyorsanız

//Your Cell Class
class TheCell: UITableViewCell {

    var callBackBlockWithParam: ((String) -> ()) = {_ in }

//Your Action on button
    @IBAction func didTap(_ sender: Any) {
        callBackBlockWithParam("Your Required Parameter like you can send button as sender or anything just change parameter type. Here I am passing string")
    }
}

//Your Controller
extension TheController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: TheCell.identifier, for: indexPath) as! TheCell {
            cell.callBackBlockWithParam = { (passedParamter) in 

             //you will get string value from cell class
                print(passedParamter)     
      }
            return cell
    }
}

0

@Mani yanıtı iyidir, ancak hücrenin içeriğindeki görünüm etiketleriGenellikle başka amaçlar için kullanılır. Bunun yerine hücrenin etiketini (veya hücrenin contentView etiketini) kullanabilirsiniz:

1) cellForRowAtIndexPath:Yönteminizde hücrenin etiketini dizin olarak atayın:

cell.tag = indexPath.row; // or cell.contentView.tag...

2) Düğmeniz için aşağıdaki gibi hedef ve eylem ekleyin:

[cell.yourbutton addTarget:self action:@selector(yourButtonClicked:) forControlEvents:UIControlEventTouchUpInside];

3) Gönderenin satırını döndüren bir yöntem oluşturun (teşekkürler @Stenio Ferreira):

- (NSInteger)rowOfSender:(id)sender
{
    UIView *superView = sender.superview;
    while (superView) {
        if ([superView isKindOfClass:[UITableViewCell class]])
            break;
        else
            superView = superView.superview;
    }

    return superView.tag;
}

4) İndekse dayalı kod eylemleri:

-(void)yourButtonClicked:(UIButton*)sender
{
     NSInteger index = [self rowOfSender:sender];
     // Your code here
}

0

CustomTableCell.h bir UITableViewCell'dir:

@property (weak, nonatomic) IBOutlet UIButton *action1Button;
@property (weak, nonatomic) IBOutlet UIButton *action2Button;

İthalattan sonra MyVC.m:

@interface MYTapGestureRecognizer : UITapGestureRecognizer
@property (nonatomic) NSInteger dataint;
@end

MyVC.m içindeki "cellForRowAtIndexPath" içinde:

//CustomTableCell 
CustomTableCell *cell = (CustomTableCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

//Set title buttons
[cell.action1Button setTitle:[NSString stringWithString:NSLocalizedString(@"action1", nil)] forState:UIControlStateNormal];
[cell.action2Button setTitle:[NSString stringWithString:NSLocalizedString(@"action2", nil)] forState:UIControlStateNormal];

//Set visibility buttons
[cell.action1Button setHidden:FALSE];
[cell.action2Button setHidden:FALSE];

//Do 1 action
[cell.action1Button addTarget:self action:@selector(do1Action :) forControlEvents:UIControlEventTouchUpInside];

//Do 2 action
MYTapGestureRecognizer *action2Tap = [[MYTapGestureRecognizer alloc] initWithTarget:self action:@selector(do2Action :)];
cancelTap.numberOfTapsRequired = 1;
cancelTap.dataint = indexPath.row;
[cell.action2Button setUserInteractionEnabled:YES];
[cell.action2Button addGestureRecognizer:action2Tap];

MyVC.m:

-(void)do1Action :(id)sender{
//do some action that is not necessary fr data
}

-(void)do2Action :(UITapGestureRecognizer *)tapRecognizer{
MYTapGestureRecognizer *tap = (MYTapGestureRecognizer *)tapRecognizer;
numberTag = tap.dataint;
FriendRequest *fr = [_list objectAtIndex:numberTag];

//connect with a WS o do some action with fr data

//actualize list in tableView
 [self.myTableView reloadData];
}

-1
cell.show.tag=indexPath.row;
     [cell.show addTarget:self action:@selector(showdata:) forControlEvents:UIControlEventTouchUpInside];

-(IBAction)showdata:(id)sender
{
    UIButton *button = (UIButton *)sender;

    UIStoryboard *storyBoard;
    storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    SecondViewController *detailView = [storyBoard instantiateViewControllerWithIdentifier:@"SecondViewController"];

    detailView.string=[NSString stringWithFormat:@"%@",[_array objectAtIndex:button.tag]];

    [self presentViewController:detailView animated:YES completion:nil];

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