Bir öğe etkinleştirildiğinde indexpath.row nasıl alınır?


107

Düğmeleri olan bir tablo görünümüm var ve bunlardan birine dokunulduğunda indexpath.row'u kullanmak istiyorum. Şu anda sahip olduğum şey bu, ama her zaman 0

var point = Int()
func buttonPressed(sender: AnyObject) {
    let pointInTable: CGPoint =         sender.convertPoint(sender.bounds.origin, toView: self.tableView)
    let cellIndexPath = self.tableView.indexPathForRowAtPoint(pointInTable)
    println(cellIndexPath)
    point = cellIndexPath!.row
    println(point)
}

nokta değişkeni yerine IndexPathForSelectedRow () kullanmalı mıyım? ya da nerede kullanmalıyım?
Vincent

Yanıtlar:


168

giorashc cevabında neredeyse buna sahipti, ancak hücrenin fazladan bir contentViewkatmanı olduğu gerçeğini gözden kaçırdı . Bu nedenle, bir katman daha derine gitmeliyiz:

guard let cell = sender.superview?.superview as? YourCellClassHere else {
    return // or fatalError() or whatever
}

let indexPath = itemTable.indexPath(for: cell)

Bunun nedeni, görünüm hiyerarşisi içinde, bir tableView'in daha sonra kendi 'içerik görünümlerine' sahip olan alt görünümler olarak hücrelere sahip olmasıdır; bu nedenle, hücrenin kendisini elde etmek için bu içerik görünümünün denetimini almanız gerekir. Bunun bir sonucu olarak, düğmeniz doğrudan hücrenin içerik görünümü yerine bir alt görünümde yer alıyorsa, ona erişmek için birçok katman daha derine inmeniz gerekir.

Yukarıdakiler böyle bir yaklaşımdır, ancak mutlaka en iyi yaklaşım değildir. İşlevsel olsa da, UITableViewCellApple'ın hiçbir zaman belgelemediği, görünüm hiyerarşisi gibi ayrıntıları varsayar . Bu gelecekte değiştirilebilir ve sonuç olarak yukarıdaki kod tahmin edilemez şekilde davranabilir.

Yukarıdakilerin bir sonucu olarak, uzun ömürlülük ve güvenilirlik nedenleriyle, başka bir yaklaşım benimsemenizi tavsiye ederim. Bu başlıkta listelenen birçok alternatif var ve sizi okumanızı tavsiye ederim, ancak kişisel favorim aşağıdaki gibidir:

Hücre sınıfınızda bir kapanmanın bir özelliğini tutun, düğmenin eylem yönteminin bunu çağırmasını sağlayın.

class MyCell: UITableViewCell {
    var button: UIButton!

    var buttonAction: ((Any) -> Void)?

    @objc func buttonPressed(sender: Any) {
        self.buttonAction?(sender)
    }
}

Ardından, içinde hücrenizi oluşturduğunuzda cellForRowAtIndexPath, kapanışınıza bir değer atayabilirsiniz.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! MyCell
    cell.buttonAction = { sender in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed(closure: buttonAction, indexPath: indexPath) // <- Method on the view controller to handle button presses.
}

İşleyici kodunuzu buraya taşıyarak, zaten mevcut olan indexPathargümandan yararlanabilirsiniz. Bu, belgelenmemiş özelliklere dayanmadığı için yukarıda listelenen çok daha güvenli bir yaklaşımdır.


2
İyi tespit edildi. Yetkili bir geliştiriciyim, söz veriyorum;) - Cevabımı değiştirdim.
Jacob Kral

12
Bu, hücreyi bir düğmeden almanın uygun yolu değil. Bir hücrenin düzeni yıllar içinde değişmiştir ve böyle bir kod, bu olduğunda çalışmayacaktır. Bu yaklaşımı kullanmayın.
rmaddy

11
Bu kötü bir çözüm. Apple'ın asla kabul etmediği UITableViewCells hakkında ayrıntıları varsayar. UITableViewCells bir contentView özelliğine sahipken, contentView'in süpervizörünün her zaman Hücre olacağına dair bir garanti yoktur.
bpapa

1
@PintuRajput Görüş hiyerarşinizi bana açıklar mısınız lütfen? Bunu, büyük olasılıkla düğmeniz hücrenin içerik görünümünün doğrudan bir alt görünümü olmadığı için görüyorsunuz.
Jacob Kral

2
@ymutlu Kesinlikle katılıyorum, bunu cevapta belirtmiştim. Ayrıca çok daha sağlam bir çözüm önerdim. Orijinali yerinde bırakmamın nedeni, diğer geliştiricilere sorunları tamamen atlatmaktansa bir yaklaşımla göstermenin daha iyi olduğunu düşünmemdir, bu onlara gördüğünüz hiçbir şeyi öğretmez. :)
Jacob King

61

Bu tür bir soruna yaklaşımım, hücre ile tablo görünümü arasında bir temsilci protokolü kullanmaktır. Bu, düğme işleyiciyi hücre alt sınıfında tutmanıza olanak tanır, bu da düğme işleyici mantığını görünüm denetleyicisinde tutarken, dokunma eylemi işleyicisini Arayüz Oluşturucu'daki prototip hücresine atamanızı sağlar.

Ayrıca, görünüm hiyerarşisinde gezinme veya taghücre indeksleri değiştiğinde (ekleme, silme veya yeniden sıralama sonucunda) sorunlara neden olan mülkün kullanımının potansiyel olarak kırılgan yaklaşımını önler.

CellSubclass.swift

protocol CellSubclassDelegate: class {
    func buttonTapped(cell: CellSubclass)
}

class CellSubclass: UITableViewCell {

@IBOutlet var someButton: UIButton!

weak var delegate: CellSubclassDelegate?

override func prepareForReuse() {
    super.prepareForReuse()
    self.delegate = nil
}

@IBAction func someButtonTapped(sender: UIButton) {
    self.delegate?.buttonTapped(self)
}

ViewController.swift

class MyViewController: UIViewController, CellSubclassDelegate {

    @IBOutlet var tableview: UITableView!

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CellSubclass

        cell.delegate = self

        // Other cell setup

    } 

    //  MARK: CellSubclassDelegate

    func buttonTapped(cell: CellSubclass) {
        guard let indexPath = self.tableView.indexPathForCell(cell) else {
            // Note, this shouldn't happen - how did the user tap on a button that wasn't on screen?
            return
        }

        //  Do whatever you need to do with the indexPath

        print("Button tapped on row \(indexPath.row)")
    }
} 

buttonTappedtemsilci işlevidir ve görünüm denetleyicisindedir. Benim örnekte, someButtonTappedhücrede aksiyon yöntemidir
Paulw11

@ paulw11 Hücrede üye yok düğmesi var Bu yöntemle Tapped@IBAction func someButtonTapped(sender: UIButton) { self.delegate?.buttonTapped(self) }
EI Kaptan v2.0

1
Bu oldukça iyi bir çözümdür (şu anda daha fazla oy alan ikisi kadar kötü değil, gözetime bakan etiketi kullanarak) ancak eklenemeyecek kadar fazla ekstra kod gibi geliyor.
bpapa

2
Bu doğru çözümdür ve kabul edilen yanıt olmalıdır. Etiket özelliğini kötüye kullanmaz, hücrelerin yapımını varsaymaz (bu, Apple tarafından kolayca değiştirilebilir) ve hücreler taşındığında veya mevcut hücreler arasına yeni hücreler eklendiğinde (ekstra kodlama olmadan) çalışmaya devam eder.
Robotik kedi

1
@ Paulw11 Başlangıçta bunun çok fazla kod olduğunu düşündüm, ancak daha önce kullandığımdan çok daha dayanıklı olduğu kanıtlandı. Bu sağlam çözümü gönderdiğiniz için teşekkür ederiz.
Adrian

54

GÜNCELLEME : Düğmeyi içeren hücrenin indexPath'ini alma (hem bölüm hem de satır):

Düğme Konumunu Kullanma

Senin içi buttonTappedo koordinat de sıranın indexPath olsun, yöntemin, sen düğmenin konumunu yakala bir tableView koordinat dönüştürmek.

func buttonTapped(_ sender:AnyObject) {
    let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
    let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
}

NOT : Bazen , bir noktada bir tableView hücresi olsa bile , işlevi kullanırken bir noktada bir satır view.convert(CGPointZero, to:self.tableView)bulurken bir uç durumla karşılaşabilirsiniz nil. Bunu düzeltmek için, aşağıdakiler gibi başlangıç ​​noktasından biraz kaymış gerçek bir koordinat geçirmeyi deneyin:

let buttonPosition:CGPoint = sender.convert(CGPoint.init(x: 5.0, y: 5.0), to:self.tableView)

Önceki Cevap: Etiket Özelliğini Kullanma (yalnızca satır döndürür)

UIButton'u tutan hücreye bir işaretçi tutmak için süpervizör ağaçlarına tırmanmak yerine, yukarıda Antonio tarafından bahsedilen, bu cevapta açıklanan ve aşağıda gösterilen button.tag özelliğini kullanan daha güvenli, daha tekrarlanabilir bir teknik vardır :

In cellForRowAtIndexPath:size etiketi özelliğini ayarlayın:

button.tag = indexPath.row
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)

Ardından, buttonClicked:işlevde, düğmenin bulunduğu indexPath satırını almak için bu etikete başvurursunuz:

func buttonClicked(sender:UIButton) {
    let buttonRow = sender.tag
}

Bu yöntemi tercih ediyorum çünkü süpervizör ağaçlarında sallanmanın bir uygulama tasarlamak için riskli bir yol olabileceğini keşfettim. Ayrıca, objektif-C için bu tekniği geçmişte kullandım ve sonuçtan memnun kaldım .


5
Bu, bunu yapmanın güzel bir yolu ve temsilcinizin biraz başlaması için ona oy vereceğim, ancak tek kusur, eğer buna da ihtiyaç duyulursa, indexPath.section'a erişim sağlamamasıdır. Yine de harika cevap!
Jacob Kral

Teşekkürler Jacob! Rep karmasını takdir ediyorum. Alacağınız istiyorsa indexPath.sectionek olarak indexPath.row(aynı etiket özelliği sıfırlamadan indexPath.section), içinde cellForRowAtIndexPath:sadece Etiketi değiştirebilir button.tag = indexPathve ardından içinde buttonClicked:fonksiyonu kullanarak hem erişebilir sender.tag.rowve sender.tag.section.
Demir John Bonney

1
Bu yeni bir özellik mi, çünkü tag özelliğinin int türünde olduğunu hatırladığıma eminim, Swift 2.3'te değişmedikçe AnyObject değil mi?
Jacob King

@JacobKing haklısın! Benim hatam, bu yorumu yazarken tamamen boşluk bıraktım ve bu etiketin AnyObject türü olduğunu düşünüyordum. Derp - bana aldırma. IndexPath'i bir etiket olarak geçebilirseniz faydalı olacaktır ...
Iron John Bonney

3
Pek de iyi bir yaklaşım değil. Birincisi, yalnızca tek bir bölümün olduğu Tablo Görünümlerinde çalışır.
bpapa

16

Herhangi bir görünüm için hücreyi getirmek üzere UITableView'a bir uzantı kullanın:


@ Paulw11'in tablo görünümüne mesajlar gönderen bir delege özelliğine sahip özel bir hücre tipi oluşturma cevabı iyi bir yoldur, ancak ayarlamak için belirli bir çalışma gerektirir.

Bence hücreyi aramak için tablo görünümü hücresinin görünüm hiyerarşisinde gezinmek kötü bir fikir. Kırılgandır - düğmenizi daha sonra yerleşim amacıyla bir görünüme eklerseniz, bu kod büyük olasılıkla kırılır.

Görünüm etiketlerini kullanmak da kırılgandır. Hücreyi oluşturduğunuzda etiketleri ayarlamayı hatırlamanız gerekir ve bu yaklaşımı başka bir amaçla görünüm etiketlerini kullanan bir görünüm denetleyicisinde kullanırsanız, yinelenen etiket numaralarına sahip olabilirsiniz ve kodunuz beklendiği gibi çalışmayabilir.

Bir tablo görünümü hücresinde bulunan herhangi bir görünüm için indexPath'i almanızı sağlayan bir UITableView uzantısı oluşturdum. Bu Optional, iletilen görünüm aslında bir tablo görünümü hücresine girmiyorsa sıfır olacak bir döndürür . Aşağıda, uzantı kaynak dosyasının tamamı bulunmaktadır. Bu dosyayı basitçe projenize yerleştirebilir ve ardından indexPathForView(_:)herhangi bir görünümü içeren indexPath'i bulmak için dahil edilen yöntemi kullanabilirsiniz .

//
//  UITableView+indexPathForView.swift
//  TableViewExtension
//
//  Created by Duncan Champney on 12/23/16.
//  Copyright © 2016-2017 Duncan Champney.
//  May be used freely in for any purpose as long as this 
//  copyright notice is included.

import UIKit

public extension UITableView {
  
  /**
  This method returns the indexPath of the cell that contains the specified view
   
   - Parameter view: The view to find.
   
   - Returns: The indexPath of the cell containing the view, or nil if it can't be found
   
  */
  
    func indexPathForView(_ view: UIView) -> IndexPath? {
        let center = view.center
        let viewCenter = self.convert(center, from: view.superview)
        let indexPath = self.indexPathForRow(at: viewCenter)
        return indexPath
    }
}

Kullanmak için, IBAction'daki yöntemi bir hücrede bulunan bir düğme için çağırmanız yeterlidir:

func buttonTapped(_ button: UIButton) {
  if let indexPath = self.tableView.indexPathForView(button) {
    print("Button tapped at indexPath \(indexPath)")
  }
  else {
    print("Button indexPath not found")
  }
}

( indexPathForView(_:)İşlevin yalnızca, iletildiği görünüm nesnesi şu anda ekranda olan bir hücre içinde yer alıyorsa çalışacağını unutmayın . Bu mantıklıdır çünkü ekranda olmayan bir görünüm aslında belirli bir indexPath'e ait değildir; hücre geri dönüştürüldüğünde farklı bir indexPath'e atanabilir.)

DÜZENLE:

Yukarıdaki uzantıyı kullanan çalışan bir demo projesini Github'dan indirebilirsiniz: TableViewExtension.git


Teşekkürler, bir hücredeki bir metin görünümünün indexPath'ini almak için uzantıyı kullandım - mükemmel çalıştı.
Jeremy Andrews

9

İçin Swift2.1

Bunu yapmanın bir yolunu buldum, umarım yardımcı olur.

let point = tableView.convertPoint(CGPoint.zero, fromView: sender)

    guard let indexPath = tableView.indexPathForRowAtPoint(point) else {
        fatalError("can't find point in tableView")
    }

Hatanın çalışması ne anlama geliyor? Noktayı tableView'de bulamamasının bazı nedenleri nelerdir?
OOProg

Bu (veya benzeri, UIView Dönüştürme yöntemlerini kullanarak) kabul edilen cevap olmalıdır. Bir tablo görünümünün özel hiyerarşisi hakkında varsayımlarda bulunmadığından, etiket özelliğini kullanmadığından (neredeyse her zaman kötü bir fikir) ve çok fazla ekstra kod içermediğinden şu anda neden 4 numara olduğundan emin değilim.
bpapa

9

Swift 4 Çözümü:

Hücrede bir düğmeniz (myButton) veya başka bir görünümünüz var. Hücreye etiket ataBunun gibi

cell.myButton.tag = indexPath.row

Şimdi içinde Fonksiyon'a veya başka birine dokunun. Bunu böyle çıkarın ve yerel bir değişkene kaydedin.

currentCellNumber = (sender.view?.tag)!

Bundan sonra, seçili düğmenin indexPath.row'unu almak için bu currentCellNumber'ı herhangi bir yerde kullanabilirsiniz.

Zevk almak!


Bu yaklaşım işe yarıyor, ancak cevabımda da belirtildiği gibi görüş etiketleri kırılgan. Örneğin, basit bir tamsayı etiketi, bölümlere ayrılmış bir tablo görünümü için çalışmaz. (bir IndexPath it 2 tamsayı.) Yaklaşımım her zaman işe yarayacak ve düğmeye (veya diğer dokunulabilir görünüme) bir etiket yüklemeye gerek yok
Duncan C

Bölümü ve satırı / öğeyi tek bir Tamsayıda kolayca saklayabilirsiniz. Cevabımı görün ...
mramosch

6

Swift 4'te şunu kullanın:

func buttonTapped(_ sender: UIButton) {
        let buttonPostion = sender.convert(sender.bounds.origin, to: tableView)

        if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
            let rowIndex =  indexPath.row
        }
}

En temiz cevap seçili olmalıdır. Unutulmaması gereken tek şey, tableViewbu cevap çalışmadan önce başvurulması gereken bir çıkış değişkenidir.
10000RubyPools

Cazibe gibi çalışın !!
Parthpatel1105

4

Index Path swift 4, 5'i almak çok basit

let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonTapped:", forControlEvents: 
UIControlEvents.TouchUpInside)

IndexPath Inside Btn Click nasıl edinilir:

func buttonTapped(_ sender: UIButton) {
     print(sender.tag)  
}

3

Olay işleyicisinin göndereni düğmenin kendisi olduğundan tag, içinde başlatılan dizini depolamak için düğmenin özelliğini kullanırdım cellForRowAtIndexPath.

Ama biraz daha fazla çalışmayla tamamen farklı bir şekilde yapardım. Özel bir hücre kullanıyorsanız, soruna şu şekilde yaklaşırım:

  • özel tablo hücresine bir "indexPath" özelliği ekleyin
  • onu başlat cellForRowAtIndexPath
  • dokunma işleyicisini görünüm denetleyicisinden hücre uygulamasına taşıyın
  • Gösterge denetleyicisine dokunma olayını bildirmek için delegasyon modelini kullanın, dizin yolunu geçerek

Antonio, özel bir cep telefonum var ve bunu senin yöntemiyle yapmak isterim. Ancak çalışmıyor. TableView commitEditingStyle yöntemi olan 'silme düğmesini ortaya çıkarmak için kaydırın' kodumun çalışmasını istiyorum. Bu kodu mainVC sınıfından kaldırdım ve customCell sınıfına koydum, ancak artık kod çalışmıyor. Neyi kaçırıyorum?
Dave G

Bence bu, x bölümlü bir hücrenin indexPath'ini almanın en iyi yolu, ancak MVC yaklaşımında 3 ve 4 numaralı madde işaretlerine ihtiyaç duymuyorum
Edward

2

Paulw11'in bir delege geri araması kullanma önerisini gördükten sonra, biraz detaylandırmak / benzer başka bir öneri öne sürmek istedim. Temsilci modelini kullanmak istemiyorsanız, kapanışları aşağıdaki gibi hızlı bir şekilde kullanabilirsiniz:

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

class Cell: UITableViewCell {
    @IBOutlet var button: UIButton!

    var buttonAction: ((sender: AnyObject) -> Void)?

    @IBAction func buttonPressed(sender: AnyObject) {
        self.buttonAction?(sender)
    }
}

Sizin cellForRowAtIndexPathyöntemi:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.buttonAction = { (sender) in
        // Do whatever you want from your button here.
    }
    // OR
    cell.buttonAction = buttonPressed // <- Method on the view controller to handle button presses.
}

2

Bir Model sınıfı kullanarak tableView ve collectionView'daki herhangi bir hücreyi yönetmek için kullanmanın çok kolay bir yolunu buldum ve bu mükemmel bir iş.

Şimdi bunu halletmenin gerçekten çok daha iyi bir yolu var. Bu, hücreyi ve değeri yönetmek için çalışacaktır.

İşte çıktım (ekran görüntüsü), bu yüzden şuna bakın:

görüntü açıklamasını buraya girin

  1. Model sınıfı oluşturmak çok basit , lütfen aşağıdaki prosedürü takip edin. İsimli swift sınıfı oluşturun RNCheckedModel, kodu aşağıdaki gibi yazın.
class RNCheckedModel: NSObject {

    var is_check = false
    var user_name = ""

    }
  1. hücre sınıfınızı oluşturun
class InviteCell: UITableViewCell {

    @IBOutlet var imgProfileImage: UIImageView!
    @IBOutlet var btnCheck: UIButton!
    @IBOutlet var lblName: UILabel!
    @IBOutlet var lblEmail: UILabel!
    }
  1. ve son olarak , UITableView'unuzu kullandığınızda UIViewController'ınızda model sınıfını kullanın .
    class RNInviteVC: UIViewController, UITableViewDelegate, UITableViewDataSource {


    @IBOutlet var inviteTableView: UITableView!
    @IBOutlet var btnInvite: UIButton!

    var checkArray : NSMutableArray = NSMutableArray()
    var userName : NSMutableArray = NSMutableArray()

    override func viewDidLoad() {
        super.viewDidLoad()
        btnInvite.layer.borderWidth = 1.5
        btnInvite.layer.cornerRadius = btnInvite.frame.height / 2
        btnInvite.layer.borderColor =  hexColor(hex: "#512DA8").cgColor

        var userName1 =["Olivia","Amelia","Emily","Isla","Ava","Lily","Sophia","Ella","Jessica","Mia","Grace","Evie","Sophie","Poppy","Isabella","Charlotte","Freya","Ruby","Daisy","Alice"]


        self.userName.removeAllObjects()
        for items in userName1 {
           print(items)


            let model = RNCheckedModel()
            model.user_name = items
            model.is_check = false
            self.userName.add(model)
        }
      }
     @IBAction func btnInviteClick(_ sender: Any) {

    }
       func tableView(_ tableView: UITableView, numberOfRowsInSection 
       section: Int) -> Int {
        return userName.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

        let image = UIImage(named: "ic_unchecked")
        cell.imgProfileImage.layer.borderWidth = 1.0
        cell.imgProfileImage.layer.masksToBounds = false
        cell.imgProfileImage.layer.borderColor = UIColor.white.cgColor
        cell.imgProfileImage.layer.cornerRadius =  cell.imgProfileImage.frame.size.width / 2
        cell.imgProfileImage.clipsToBounds = true

        let model = self.userName[indexPath.row] as! RNCheckedModel
        cell.lblName.text = model.user_name

        if (model.is_check) {
            cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)
        }
        else {
            cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)
        }

        cell.btnCheck.tag = indexPath.row
        cell.btnCheck.addTarget(self, action: #selector(self.btnCheck(_:)), for: .touchUpInside)

        cell.btnCheck.isUserInteractionEnabled = true

    return cell

    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 80

    }

    @objc func btnCheck(_ sender: UIButton) {

        let tag = sender.tag
        let indexPath = IndexPath(row: tag, section: 0)
        let cell: InviteCell = inviteTableView.dequeueReusableCell(withIdentifier: "InviteCell", for: indexPath) as! InviteCell

        let model = self.userName[indexPath.row] as! RNCheckedModel

        if (model.is_check) {

            model.is_check = false
            cell.btnCheck.setImage(UIImage(named: "ic_unchecked"), for: UIControlState.normal)

            checkArray.remove(model.user_name)
            if checkArray.count > 0 {
                btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
                print(checkArray.count)
                UIView.performWithoutAnimation {
                    self.view.layoutIfNeeded()
                }
            } else {
                btnInvite.setTitle("Invite", for: .normal)
                UIView.performWithoutAnimation {
                    self.view.layoutIfNeeded()
                }
            }

        }else {

            model.is_check = true
            cell.btnCheck.setImage(UIImage(named: "ic_checked"), for: UIControlState.normal)

            checkArray.add(model.user_name)
            if checkArray.count > 0 {
                btnInvite.setTitle("Invite (\(checkArray.count))", for: .normal)
                UIView.performWithoutAnimation {
                self.view.layoutIfNeeded()
                }
            } else {
                 btnInvite.setTitle("Invite", for: .normal)
            }
        }

        self.inviteTableView.reloadData()
    }

    func hexColor(hex:String) -> UIColor {
        var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

        if (cString.hasPrefix("#")) {
            cString.remove(at: cString.startIndex)
        }

        if ((cString.count) != 6) {
            return UIColor.gray
        }

        var rgbValue:UInt32 = 0
        Scanner(string: cString).scanHexInt32(&rgbValue)

        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(1.0)
        )
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

     }

1

Tablo görünümünden nokta almak için convertPoint yöntemini kullandım ve indexPath'i almak için bu noktayı indexPathForRowAtPoint yöntemine geçirdim

 @IBAction func newsButtonAction(sender: UIButton) {
        let buttonPosition = sender.convertPoint(CGPointZero, toView: self.newsTableView)
        let indexPath = self.newsTableView.indexPathForRowAtPoint(buttonPosition)
        if indexPath != nil {
            if indexPath?.row == 1{
                self.performSegueWithIdentifier("alertViewController", sender: self);
            }   
        }
    }

1

IBaction'ı çağırmak için #selector kullanmayı deneyin. Cellforrowatindexpath

            cell.editButton.tag = indexPath.row
        cell.editButton.addTarget(self, action: #selector(editButtonPressed), for: .touchUpInside)

Bu şekilde, editButtonPressed yönteminin içindeki dizin yoluna erişebilirsiniz.

func editButtonPressed(_ sender: UIButton) {

print(sender.tag)//this value will be same as indexpath.row

}

En uygun cevap
Amalendu Kar

Hayır, kullanıcı hücre eklediğinde veya çıkardığında etiketler kapalı olacaktır.
koen

@koen: Ekledikten veya sildikten sonra tableView'i yeniden yüklerseniz olmaz ;-)
mramosch

1

Benim durumumda birden fazla bölümüm var ve hem bölüm hem de satır indeksi hayati önem taşıyor, bu yüzden böyle bir durumda UIButton'da hücre indexPath'i şu şekilde ayarladığım bir özellik oluşturdum:

fileprivate struct AssociatedKeys {
    static var index = 0
}

extension UIButton {

    var indexPath: IndexPath? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.index) as? IndexPath
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.index, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

Ardından özelliği cellForRowAt içinde şu şekilde ayarlayın:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
    cell.button.indexPath = indexPath
}

Daha sonra handleTapAction'da indexPath'i şu şekilde alabilirsiniz:

@objc func handleTapAction(_ sender: UIButton) {
    self.selectedIndex = sender.indexPath

}

1

Swift 4 ve 5

Protokol temsilcisi kullanarak Yöntem 1

Örneğin, bir UITableViewCelladınız varMyCell

class MyCell: UITableViewCell {
    
    var delegate:MyCellDelegate!
    
    @IBAction private func myAction(_ sender: UIButton){
        delegate.didPressButton(cell: self)
    }
}

Şimdi bir protocol

protocol MyCellDelegate {
    func didPressButton(cell: UITableViewCell)
}

Sonraki adımda bir Uzantı oluşturun UITableView

extension UITableView {
    func returnIndexPath(cell: UITableViewCell) -> IndexPath?{
        guard let indexPath = self.indexPath(for: cell) else {
            return nil
        }
        return indexPath
    }
}

Gözlerinde farklı UIViewControllerprotokol uygulamakMyCellDelegate

class ViewController: UIViewController, MyCellDelegate {
     
    func didPressButton(cell: UITableViewCell) {
        if let indexpath = self.myTableView.returnIndexPath(cell: cell) {
              print(indexpath)
        }
    }
}

Kapatma kullanarak Yöntem 2

İçinde UIViewController

override func viewDidLoad() {
        super.viewDidLoad()
       //using the same `UITableView extension` get the IndexPath here
        didPressButton = { cell in
            if let indexpath = self.myTableView.returnIndexPath(cell: cell) {
                  print(indexpath)
            }
        }
    }
 var didPressButton: ((UITableViewCell) -> Void)

class MyCell: UITableViewCell {

    @IBAction private func myAction(_ sender: UIButton){
        didPressButton(self)
    }
}

Not: - UICollectionViewindexPath'i almak istiyorsanız, bunu kullanabilir UICollectionView extensionve yukarıdaki adımları tekrarlayabilirsiniz.

extension UICollectionView {
    func returnIndexPath(cell: UICollectionViewCell) -> IndexPath?{
        guard let indexPath = self.indexPath(for: cell) else {
            return nil
        }
        return indexPath
    }
}

0

Swift 3'te ayrıca uzun zincir zincirinden kaçınarak koruma ifadeleri kullandı.

func buttonTapped(sender: UIButton) {
    guard let cellInAction = sender.superview as? UITableViewCell else { return }
    guard let indexPath = tableView?.indexPath(for: cellInAction) else { return }

    print(indexPath)
}

Bu işe yaramayacak. Düğmenin denetleme görünümü hücre olmayacaktır.
rmaddy

Bu işe yarıyor. Dikkat etmeniz gereken tek şey, herkesin görüş yığınının farklı olmasıdır. Sender.superview, sender.superview.superview veya sender.superview.superview.superview olabilir. Ama gerçekten iyi çalışıyor.
Sean

0

Bazen düğmesi başka bir UITableViewCell görünümünün içinde olabilir. Bu durumda süpervizör görünüm.superview hücre nesnesini vermeyebilir ve bu nedenle indexPath sıfır olacaktır.

Bu durumda, hücre nesnesini alana kadar süpervizyonu bulmaya devam etmeliyiz.

Gözetim ile hücre nesnesini alma işlevi

func getCellForView(view:UIView) -> UITableViewCell?
{
    var superView = view.superview

    while superView != nil
    {
        if superView is UITableViewCell
        {
            return superView as? UITableViewCell
        }
        else
        {
            superView = superView?.superview
        }
    }

    return nil
}

Şimdi aşağıdaki gibi düğmeye dokunarak indexPath alabiliriz

@IBAction func tapButton(_ sender: UIButton)
{
    let cell = getCellForView(view: sender)
    let indexPath = myTabelView.indexPath(for: cell)
}

0
// CustomCell.swift

protocol CustomCellDelegate {
    func tapDeleteButton(at cell: CustomCell)
}

class CustomCell: UICollectionViewCell {
    
    var delegate: CustomCellDelegate?
    
    fileprivate let deleteButton: UIButton = {
        let button = UIButton(frame: .zero)
        button.setImage(UIImage(named: "delete"), for: .normal)
        button.addTarget(self, action: #selector(deleteButtonTapped(_:)), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    @objc fileprivate func deleteButtonTapped(_sender: UIButton) {
        delegate?.tapDeleteButton(at: self)
    }
    
}

//  ViewController.swift

extension ViewController: UICollectionViewDataSource {

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: customCellIdentifier, for: indexPath) as? CustomCell else {
            fatalError("Unexpected cell instead of CustomCell")
        }
        cell.delegate = self
        return cell
    }

}

extension ViewController: CustomCellDelegate {

    func tapDeleteButton(at cell: CustomCell) {
        // Here we get the indexPath of the cell what we tapped on.
        let indexPath = collectionView.indexPath(for: cell)
    }

}

0

SATIRLAR VE BÖLÜMLER İÇİN TEK ETİKET KULLANMA

Satır / öğe VE bir TableView / CollectionView bölümünün aynı anda iletilmesi için etiketleri kullanmanın basit bir yolu vardır.

Kodlayın indexPath da UIView.tag için cellForRowAtIndexPath :

buttonForCell.tag = convertIndexPathToTag(with: indexPath)

Decode indexPath hedef seçicisi içinde göndericiden:

    @IBAction func touchUpInsideButton(sender: UIButton, forEvent event: UIEvent) {

        var indexPathForButton = convertTagToIndexPath(from: sender)

    }

Kodlayıcı ve Kod Çözücü:

func convertIndexPathToTag(indexPath: IndexPath) -> Int {
    var tag: Int = indexPath.row + (1_000_000 * indexPath.section)
    
    return tag
}

func convertTagToIndexPath(from sender: UIButton) -> IndexPath {
    var section: Int = Int((Float(sender.tag) / 1_000_000).rounded(.down))
    var row: Int = sender.tag - (1_000_000 * section)

    return IndexPath(row: row, section: section)
}

32 bit cihazda 4294967296'dan fazla satıra / öğeye ihtiyacınız olmaması koşuluyla ;-) örn.

  • 100_000 öğe / satır ile 42949 bölüm
  • 1_000_000 öğe / satır içeren 4294 bölüm - ( yukarıdaki örnekte olduğu gibi )
  • 10_000_000 öğe / satır ile 429 bölüm

—-

UYARI: TableView / CollectionView'unuzda satırları / öğeleri silerken veya eklerken, düğmelerinizin etiket numaralarını modelinizle senkronize tutmak için ekleme / silme noktanızdan sonra tüm satırları / öğeleri yeniden yüklemeniz gerektiğini unutmayın.

—-

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.