UITableViewCell'in aksesuarView için özel bir görüntü kullanma ve UITableViewDelegate'e yanıt vermesini sağlama


139

Hücre için aynı dahil olmak üzere özel bir çizilmiş UITableViewCell kullanıyorum accessoryView. AccessoriesView için kurulumum böyle bir şeyle olur:

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

Ayrıca hücre başlatıldığında, initWithFrame:reuseIdentifier:I kullanarak aşağıdaki özelliği ayarlamak için emin olun:

self.userInteractionEnabled = YES;

Ne yazık ki benim UITableViewDelegate, benim tableView:accessoryButtonTappedForRowWithIndexPath:yöntem (10 kez tekrar deneyin) tetiklenmiyor. Delege kesinlikle doğru şekilde bağlanmış.

Ne eksik olabilir?

Hepinize teşekkürler.

Yanıtlar:


228

Ne yazık ki, önceden tanımlanmış türlerden birini kullandığınızda sağlanan dahili düğme türüne dokunulmadığı sürece bu yöntem çağrılmaz. Kendinizinkini kullanmak için, aksesuarınızı bir düğme veya diğer UIControl alt sınıfı olarak oluşturmanız gerekir ( -buttonWithType:UIButtonTypeCustombir UIImageView kullanmak yerine düğmenin görüntüsünü kullanarak ve ayarlayarak bir düğme öneriyorum ).

İşte Outpost'ta kullandığım bazı şeyleri, diğer tüm tablo görünümlerinin kullanması için yardımcı program kodunu tutmak için kendi UITableViewController aracı alt sınıfımı yaparak yaraladığım standart widget'ların (sadece biraz, deniz mavisi renklendirmemizle eşleşecek şekilde) özelleştirmesini sağlayan bazı şeyler var (şimdi alt sınıflar) OPTableViewController).

İlk olarak, bu fonksiyon özel grafiğimizi kullanarak yeni bir detay açıklama düğmesi döndürür:

- (UIButton *) makeDetailDisclosureButton
{
    UIButton * button = [UIButton outpostDetailDisclosureButton];

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

    return ( button );
}

Düğme tamamlandığında bu rutini çağıracak ve daha sonra aksesuar düğmeleri için standart UITableViewDelegate rutini besleyecektir:

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

Bu işlev, düğmenin sağladığı olaydan bir dokunuşun tablo görünümündeki konumunu alarak ve o noktadaki satırın dizin yolu için tablo görünümü sorarak satırı bulur.


Teşekkürler Jim. Özel bir imageView ile neden yapamadığımı merak etmek için 20 dakikadan fazla zaman harcadığım için çok yazık. Bunu Apple'ın örnek Aksesuar uygulamasında nasıl yapacağımı gördüm. Cevabınız iyi açıklanmış ve belgelenmiştir, bu yüzden onu işaretliyorum ve saklıyorum. Tekrar teşekkürler. :-)

Jim, harika cevap. Bir potansiyel sorun (en azından benim ucumda) - Düğmeye kayıt dokunuşlarını almak için aşağıdaki satırı eklemek zorunda kaldım: button.userInteractionEnabled = YES;
Mike Laurence

11
Sadece bu cevaba bakan diğerleri için, aynı zamanda satıra karşılık gelen düğmeye bir etiket koyabilirsiniz (birden fazla bölümünüz varsa, biraz matematik yapmanız gerekir) ve ardından etiketi içindeki düğmeden dışarı çekebilirsiniz. işlev. Bence dokunuşu hesaplamaktan biraz daha hızlı olabilir.
RyanJM

3
bu, sabit kodlamanızı gerektirir self.tableView. hangi tablo görünümünün satırı içerdiğini bilmiyorsanız ne olur?
user102008

4
@RyanJM Bir hitTest yapmanın aşırı olduğunu ve etiketlerin yeterli olacağını düşünürdüm. Aslında bazı kod benim etiketleri fikir kullanmış. Ancak bugün kullanıcının yeni satır ekleyebileceği bir sorunla karşılaştım. Bu, etiketleri kullanarak kesmek öldürür. Jim Dovey tarafından önerilen çözüm (ve Apple'ın örnek kodunda görüldüğü gibi) genel bir çözümdür ve her durumda çalışır
srik

77

Bu web sitesini çok yardımcı buldum: iphone'daki uitableview için özel aksesuar görünümü

Kısacası, bunu şu dillerde kullanın 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;

ardından bu yöntemi uygulayın:

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

4
Apple'ın dokümanlarında örnek kodlarında önerdiği şey için +1 diyebilirim: developer.apple.com/library/ios/#samplecode/Accessory/Listings/…
cleverbit

Çerçeveyi ayarlamak benim için eksik parçaydı. Ayrıca herhangi bir metin istemediğiniz sürece setImage (arka plan yerine) de ayarlayabilirsiniz.
Jeremy Hicks

1
Bağlantı @ richarddas'ın cevabında koptu. Yeni Bağlantı: developer.apple.com/library/prerelease/ios/samplecode/Accessory/…
delavega66

7

Benim yaklaşımım bir UITableViewCellalt sınıf oluşturmak ve UITableViewDelegateiçinde olağan 'yöntem çağıracak mantığı kapsüllemek .

// 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

Bu EN İYİ cevap. Ama button.superview, cell.superviewve [tableView.delegate tableView:...]güvenli yeterli değildir.
Bay Ming

3

Jim Dovey'in yukarıdaki cevabına bir uzantı:

UITableView'ınızla birlikte bir UISearchBarController kullanırken dikkatli olun. Bu durumda, kontrol etmek self.searchDisplayController.activeve kullanmak self.searchDisplayController.searchResultsTableViewyerineself.tableView . Aksi takdirde, searchDisplayController etkin olduğunda, özellikle de arama sonuçları kaydırıldığında beklenmedik sonuçlar alırsınız.

Örneğin:

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

2
  1. Düğme etiketleri için bir makro tanımlayın:

    #define AccessoryViewTagSinceValue 100000 // (AccessoryViewTagSinceValue * sections + rows) must be LE NSIntegerMax
  2. Hücre oluştururken Oluştur düğmesini ve hücreyi ayarlayın. AccessoryView

    UIButton *accessoryButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
    accessoryButton.frame = CGRectMake(0, 0, 30, 30);
    [accessoryButton addTarget:self action:@selector(accessoryButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
    cell.accessoryView = accessoryButton;
  3. Cell.accessoryView.tag öğesini indexPath ile UITableViewDataSource yönteminde ayarlayın -tableView: cellForRowAtIndexPath:

    cell.accessoryView.tag = indexPath.section * AccessoryViewTagSinceValue + indexPath.row;
  4. Düğmeler için olay işleyici

    - (void) accessoryButtonTapped:(UIButton *)button {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:button.tag % AccessoryViewTagSinceValue
                                                    inSection:button.tag / AccessoryViewTagSinceValue];
    
        [self.tableView.delegate tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
    }
  5. UITableViewDelegate yöntemini uygulama

    - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
        // do sth.
    }

1
tagMutlak gerekli olmadığı sürece, başka bir çözüm aramadıkça kimse kullanmamalıdır .
Lifely

2

Düğmeye dokunulduğunda, bir UITableViewCell alt sınıfı içinde aşağıdaki yöntemi çağırmasını sağlayabilirsiniz.

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

 }

1

Yanchenko yaklaşımıyla eklemek zorunda kaldım: [accBtn setFrame:CGRectMake(0, 0, 20, 20)];

TableCell'inizi özelleştirmek için xib dosyası kullanıyorsanız initWithStyle: reuseIdentifier: wont get call.

Bunun yerine geçersiz kılma:

-(void)awakeFromNib
{
//Put your code here 

[super awakeFromNib];

}

1

UIControlOlay dağıtımını UIButtonbasit yerine düzgün bir şekilde almak için (örneğin a ) kullanmanız gerekir UIView/UIImageView.


1

Hızlı 5

Bu yaklaşım, UIButton.tagtemel bit kaydırma özelliğini kullanarak indexPath öğesini depolamak için kullanır . Bu yaklaşım, 65535 bölümden veya satıra sahip olmadığınız sürece 32 ve 64 bit sistemlerde çalışacaktır.

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
}

0

İOS 3.2'den itibaren, burada başkalarının önerdiği düğmelerden kaçınabilir ve bunun yerine bir dokunma hareketi tanıyıcı ile UIImageView kullanabilirsiniz. UIImageViews uygulamasında varsayılan olarak kapalı olan kullanıcı etkileşimini etkinleştirdiğinizden emin olun.

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.