Bagaimana cara mendapatkan indexpath.row ketika sebuah elemen diaktifkan?

104

Saya memiliki tampilan tabel dengan tombol dan saya ingin menggunakan indexpath.row ketika salah satunya diketuk. Ini yang saat ini saya miliki, tetapi selalu 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)
}
Vincent
sumber
haruskah saya menggunakan IndexPathForSelectedRow () sebagai ganti variabel point? atau di mana saya harus menggunakannya?
Vincent

Jawaban:

164

giorashc hampir mendapatkannya dengan jawabannya, tetapi dia mengabaikan fakta bahwa sel memiliki contentViewlapisan ekstra . Jadi, kita harus melangkah lebih dalam:

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

let indexPath = itemTable.indexPath(for: cell)

Ini karena dalam hierarki tampilan, tableView memiliki sel sebagai subview yang kemudian memiliki 'tampilan konten' sendiri, inilah mengapa Anda harus mendapatkan tampilan super tampilan konten ini untuk mendapatkan sel itu sendiri. Akibatnya, jika tombol Anda berada dalam subview dan bukan langsung ke tampilan konten sel, Anda harus masuk lebih dalam beberapa lapisan untuk mengaksesnya.

Di atas adalah salah satu pendekatan seperti itu, tetapi belum tentu merupakan pendekatan terbaik. Meskipun berfungsi, ini mengasumsikan detail tentang UITableViewCellyang belum pernah didokumentasikan Apple, seperti hierarki tampilan. Ini dapat diubah di masa mendatang, dan akibatnya kode di atas mungkin berperilaku tidak terduga.

Sebagai hasil dari hal di atas, untuk alasan umur panjang dan keandalan, saya sarankan untuk mengadopsi pendekatan lain. Ada banyak alternatif yang tercantum di utas ini, dan saya mendorong Anda untuk membaca, tetapi favorit pribadi saya adalah sebagai berikut:

Pegang properti closure pada kelas sel Anda, minta metode aksi tombol memanggil ini.

class MyCell: UITableViewCell {
    var button: UIButton!

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

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

Kemudian, saat Anda membuat sel cellForRowAtIndexPath, Anda dapat menetapkan nilai untuk closure Anda.

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

Dengan memindahkan kode penangan Anda di sini, Anda dapat memanfaatkan indexPathargumen yang sudah ada . Ini adalah pendekatan yang jauh lebih aman daripada yang disebutkan di atas karena tidak bergantung pada sifat yang tidak terdokumentasi.

Jacob King
sumber
2
Terlihat bagus. Saya seorang pengembang yang kompeten, saya berjanji;) - Telah mengubah jawaban saya.
Jacob King
12
Ini bukanlah cara yang tepat untuk mendapatkan sel dari sebuah tombol. Tata letak sel telah berubah selama bertahun-tahun dan kode seperti ini akan gagal berfungsi saat itu terjadi. Jangan gunakan pendekatan ini.
rmaddy
11
Ini adalah solusi yang buruk. Ini mengasumsikan detail tentang UITableViewCells yang belum pernah disetujui Apple. Meskipun UITableViewCells memiliki properti contentView, tidak ada jaminan bahwa superview contentView akan selalu menjadi Cell.
bpapa
1
@PintuRajput Bisakah Anda menjelaskan hierarki tampilan Anda kepada saya? Anda mungkin melihat ini karena tombol Anda bukan subview langsung dari tampilan konten sel.
Jacob King
2
@ymutlu Saya sangat setuju, saya menyatakan ini dalam jawaban. Saya juga mengusulkan solusi yang jauh lebih kuat. Alasan saya meninggalkan aslinya adalah karena saya merasa lebih baik menunjukkan kepada developer lain masalah dengan pendekatan daripada menghindarinya sama sekali, ini tidak mengajarkan mereka apa pun yang Anda lihat. :)
Jacob King
61

Pendekatan saya untuk masalah semacam ini adalah dengan menggunakan protokol delegasi antara sel dan tampilan tabel. Hal ini memungkinkan Anda untuk mempertahankan penangan tombol dalam subkelas sel, yang memungkinkan Anda menetapkan penangan tindakan sentuhan ke sel prototipe di Pembuat Antarmuka, sambil tetap mempertahankan logika penangan tombol di pengontrol tampilan.

Ini juga menghindari pendekatan yang berpotensi rapuh dalam menavigasi hierarki tampilan atau penggunaan tagproperti, yang memiliki masalah saat indeks sel berubah (sebagai akibat dari penyisipan, penghapusan, atau penyusunan ulang)

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)")
    }
} 
Paulw11
sumber
buttonTappedadalah fungsi delegasi dan dalam pengontrol tampilan. Dalam contoh saya, someButtonTappedadalah metode tindakan dalam sel
Paulw11
@ paulw11 Saya mendapat sel tidak memiliki tombol anggota Ketuk dalam metode ini@IBAction func someButtonTapped(sender: UIButton) { self.delegate?.buttonTapped(self) }
EI Captain v2.0
1
Ini adalah solusi yang cukup bagus (tidak seburuk keduanya saat ini dengan lebih banyak suara, menggunakan tag melihat superview) tetapi rasanya terlalu banyak kode tambahan untuk ditambahkan.
bpapa
2
Ini adalah solusi yang benar dan harus menjadi jawaban yang diterima. Itu tidak menyalahgunakan properti tag, tidak mengasumsikan konstruksi sel (yang dapat dengan mudah diubah oleh Apple) dan akan tetap berfungsi (tanpa pengkodean tambahan) ketika sel dipindahkan atau sel baru ditambahkan di antara sel yang ada.
Kucing Robot
1
@ Paulw11 Awalnya saya mengira ini banyak kode, tetapi terbukti jauh lebih tangguh daripada yang saya gunakan sebelumnya. Terima kasih telah memposting solusi kuat ini.
Adrian
53

UPDATE : Mendapatkan indexPath dari sel yang berisi tombol (bagian dan baris):

Menggunakan Posisi Tombol

Di dalam buttonTappedmetode Anda, Anda dapat mengambil posisi tombol, mengubahnya menjadi koordinat di tableView, lalu mendapatkan indexPath dari baris pada koordinat tersebut.

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

CATATAN : Kadang-kadang Anda bisa mengalami kasus tepi saat menggunakan view.convert(CGPointZero, to:self.tableView)hasil fungsi dalam menemukan nilbaris pada suatu titik, meskipun ada sel tableView di sana. Untuk memperbaikinya, coba berikan koordinat nyata yang sedikit diimbangi dari asalnya, seperti:

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

Jawaban Sebelumnya: Menggunakan Properti Tag (hanya mengembalikan baris)

Daripada naik ke pohon superview untuk mengambil penunjuk ke sel yang menahan tombol UIButton, ada teknik yang lebih aman dan dapat diulang dengan menggunakan properti button.tag yang disebutkan oleh Antonio di atas, dijelaskan dalam jawaban ini , dan ditunjukkan di bawah ini:

Di cellForRowAtIndexPath:Anda mengatur properti tag:

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

Kemudian, dalam buttonClicked:fungsinya, Anda mereferensikan tag itu untuk mengambil baris indexPath tempat tombol berada:

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

Saya lebih suka metode ini karena saya telah menemukan bahwa berayun di pohon superview bisa menjadi cara yang berisiko untuk mendesain aplikasi. Juga, untuk tujuan-C saya telah menggunakan teknik ini di masa lalu dan senang dengan hasilnya.

Besi John Bonney
sumber
5
Ini adalah cara yang bagus untuk melakukannya, dan saya akan memberi suara positif untuk memulai sedikit perwakilan Anda, namun satu-satunya kekurangannya adalah tidak memberikan akses ke indexPath.section jika ini juga diperlukan. Jawaban yang bagus!
Jacob King
Terima kasih Jacob! Saya menghargai rep karma. Jika Anda ingin mendapatkan indexPath.sectiontambahan ke indexPath.row(tanpa menyetel ulang properti tag sebagai indexPath.section), di dalam cellForRowAtIndexPath:Anda cukup mengubah tag menjadi button.tag = indexPath, dan kemudian di dalam buttonClicked:fungsi Anda bisa mengakses keduanya dengan menggunakan sender.tag.rowdan sender.tag.section.
Iron John Bonney
1
Apakah ini fitur baru, karena saya yakin saya ingat properti tag bertipe Int bukan tipe AnyObject, kecuali jika diubah di swift 2.3?
Jacob King
@JobKing Anda benar! Salah saya, saya benar-benar memberi jarak saat menulis komentar itu dan berpikir bahwa tag itu adalah tipe AnyObject. Derp - jangan pedulikan aku. Akan berguna jika Anda bisa meneruskan indexPath sebagai tag ...
Iron John Bonney
3
Bukan pendekatan yang bagus juga. Untuk satu hal, ini hanya akan berfungsi di Tampilan Tabel di mana terdapat satu bagian.
bpapa
16

Gunakan ekstensi ke UITableView untuk mengambil sel untuk tampilan apa pun:


Jawaban @ Paulw11 untuk menyiapkan tipe sel kustom dengan properti delegasi yang mengirim pesan ke tampilan tabel adalah cara yang baik untuk dilakukan, tetapi memerlukan sejumlah pekerjaan untuk menyiapkan.

Saya pikir menjalankan hierarki tampilan sel tampilan tabel mencari sel adalah ide yang buruk. Ini rapuh - jika nanti Anda mengapit tombol Anda dalam tampilan untuk tujuan tata letak, kode tersebut kemungkinan besar akan rusak.

Menggunakan tag tampilan juga rapuh. Anda harus ingat untuk menyiapkan tag saat Anda membuat sel, dan jika Anda menggunakan pendekatan itu dalam pengontrol tampilan yang menggunakan tag tampilan untuk tujuan lain, Anda dapat memiliki nomor tag duplikat dan kode Anda bisa gagal berfungsi seperti yang diharapkan.

Saya telah membuat ekstensi ke UITableView yang memungkinkan Anda mendapatkan indexPath untuk tampilan apa pun yang terdapat dalam sel tampilan tabel. Ini mengembalikan nilai Optionalyang akan menjadi nol jika tampilan yang diteruskan sebenarnya tidak termasuk dalam sel tampilan tabel. Di bawah ini adalah file sumber ekstensi secara keseluruhan. Anda cukup meletakkan file ini di proyek Anda dan kemudian menggunakan indexPathForView(_:)metode yang disertakan untuk menemukan indexPath yang berisi tampilan apa pun.

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

Untuk menggunakannya, Anda cukup memanggil metode di IBAction untuk tombol yang ada di dalam sel:

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

(Perhatikan bahwa indexPathForView(_:)fungsi ini hanya akan berfungsi jika objek tampilan yang diteruskannya berisi sel yang saat ini ada di layar. Itu wajar, karena tampilan yang tidak ada di layar sebenarnya bukan milik indexPath tertentu; ditetapkan ke indexPath yang berbeda ketika itu berisi sel didaur ulang.)

EDIT:

Anda dapat mengunduh proyek demo yang berfungsi yang menggunakan ekstensi di atas dari Github: TableViewExtension.git

Duncan C
sumber
Terima kasih saya menggunakan ekstensi untuk mendapatkan indexPath dari textview dalam sel - bekerja dengan sempurna.
Jeremy Andrews
9

Untuk Swift2.1

Saya menemukan cara untuk melakukannya, semoga, ini akan membantu.

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

    guard let indexPath = tableView.indexPathForRowAtPoint(point) else {
        fatalError("can't find point in tableView")
    }
petugas khusus
sumber
Apa artinya jika error berjalan? Apa beberapa alasan mengapa ia tidak dapat menemukan titik di tableView?
OOProg
Ini (atau serupa, menggunakan metode UIView Converting) harus menjadi jawaban yang diterima. Tidak yakin mengapa saat ini # 4, karena tidak membuat asumsi tentang hierarki pribadi tampilan tabel, tidak menggunakan properti tag (hampir selalu merupakan ide yang buruk), dan tidak melibatkan banyak kode tambahan.
bpapa
9

Solusi Swift 4:

Anda memiliki tombol (myButton) atau tampilan lain di sel. Tetapkan tag di cellForRowAt seperti ini

cell.myButton.tag = indexPath.row

Sekarang di Anda tapFungsi atau lainnya. Ambil seperti ini dan simpan dalam variabel lokal.

currentCellNumber = (sender.view?.tag)!

Setelah ini, Anda dapat menggunakan di mana saja currentCellNumber ini untuk mendapatkan indexPath.row dari tombol yang dipilih.

Nikmati!

Sajid Zeb
sumber
Pendekatan itu berfungsi, tetapi tag tampilan rapuh, seperti yang disebutkan dalam jawaban saya. Tag bilangan bulat sederhana tidak akan berfungsi untuk tampilan tabel bagian, misalnya. (sebuah IndexPath it 2 integer.) Pendekatan saya akan selalu berfungsi, dan tidak perlu memasang tag ke tombol (atau tampilan lain yang dapat disadap.)
Duncan C
6

Di Swift 4, cukup gunakan ini:

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

        if let indexPath = tableView.indexPathForRow(at: buttonPostion) {
            let rowIndex =  indexPath.row
        }
}
DEEPAK KUMAR
sumber
Jawaban terbersih, harus dipilih. Satu-satunya hal yang perlu diperhatikan adalah tableViewvariabel outlet yang perlu direferensikan sebelum jawaban ini berfungsi.
10000RubyPools
Bekerja seperti pesona !!
Parthpatel1105
4

Sangat Sederhana mendapatkan Jalur Indeks 4, 5

 let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
  cell.btn.tag = indexPath.row


  cell.btn.addTarget(self, action: "buttonTapped:", forControlEvents: 
UIControlEvents.TouchUpInside)

Cara mendapatkan IndexPath Inside Btn Click:

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


}
M Murteza
sumber
3

Karena pengirim event handler adalah tombol itu sendiri, saya akan menggunakan tagproperti tombol untuk menyimpan indeks, diinisialisasi dalam cellForRowAtIndexPath.

Tetapi dengan sedikit lebih banyak pekerjaan yang akan saya lakukan dengan cara yang sama sekali berbeda. Jika Anda menggunakan sel khusus, inilah cara saya mendekati masalahnya:

  • tambahkan properti 'indexPath` ke sel tabel kustom
  • menginisialisasi di cellForRowAtIndexPath
  • pindahkan penangan ketukan dari pengontrol tampilan ke implementasi sel
  • gunakan pola delegasi untuk memberi tahu pengontrol tampilan tentang peristiwa tap, dengan meneruskan jalur indeks
Antonio
sumber
Antonio, saya memiliki sel khusus dan akan senang melakukannya dengan cara Anda. Namun, itu tidak berhasil. Saya ingin kode 'geser untuk mengungkapkan tombol hapus' saya untuk dijalankan, yang merupakan metode tableView commitEditingStyle. Saya menghapus kode itu dari kelas mainVC dan meletakkannya di kelas customCell, tetapi sekarang kodenya tidak lagi berfungsi. Apa yang saya lewatkan?
Dave G
Saya pikir ini adalah cara terbaik untuk mendapatkan indexPath dari sel dengan bagian x, namun saya tidak melihat perlunya poin-poin 3 dan 4 dalam pendekatan MVC
Edward
2

Setelah melihat saran Paulw11 untuk menggunakan panggilan balik delegasi, saya ingin menguraikannya sedikit / mengajukan saran lain yang serupa. Jika Anda tidak ingin menggunakan pola delegasi, Anda dapat menggunakan closure dengan cepat sebagai berikut:

Kelas sel Anda:

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

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

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

cellForRowAtIndexPathMetode Anda :

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.
}
Jacob King
sumber
2

Saya menemukan cara yang sangat mudah untuk digunakan untuk mengelola sel apa pun di tableView dan collectionView dengan menggunakan kelas Model dan ini berfungsi dengan sempurna.

Memang ada cara yang jauh lebih baik untuk menangani hal ini sekarang. Ini akan berfungsi untuk mengelola sel dan nilai.

Ini keluaran saya (tangkapan layar) jadi lihat ini:

masukkan deskripsi gambar di sini

  1. Sangat mudah untuk membuat kelas model , ikuti prosedur di bawah ini. Buat kelas swift dengan nama RNCheckedModel, tulis kodenya seperti dibawah ini.
class RNCheckedModel: NSObject {

    var is_check = false
    var user_name = ""

    }
  1. buat kelas sel Anda
class InviteCell: UITableViewCell {

    @IBOutlet var imgProfileImage: UIImageView!
    @IBOutlet var btnCheck: UIButton!
    @IBOutlet var lblName: UILabel!
    @IBOutlet var lblEmail: UILabel!
    }
  1. dan terakhir gunakan kelas model di UIViewController saat Anda menggunakan UITableView .
    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()

    }

     }
Paresh Mangukiya
sumber
1

Saya menggunakan metode convertPoint untuk mendapatkan poin dari tableview dan meneruskan titik ini ke metode indexPathForRowAtPoint untuk mendapatkan indexPath

 @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);
            }   
        }
    }
Avijit Nagare
sumber
1

Coba gunakan #selector untuk memanggil IBaction.In cellforrowatindexpath

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

Dengan cara ini Anda dapat mengakses jalur indeks di dalam metode editButtonPressed

func editButtonPressed(_ sender: UIButton) {

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

}
Vineeth Krishnan
sumber
Jawaban paling tepat
Amalendu Kar
Tidak, tag akan dinonaktifkan saat pengguna menambah atau menghapus sel.
koen
1

Dalam kasus saya, saya memiliki beberapa bagian dan indeks bagian dan baris sangat penting, jadi dalam kasus seperti itu saya baru saja membuat properti di UIButton yang saya atur sel indexPath seperti ini:

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

Kemudian setel properti di cellForRowAt seperti ini:

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

Kemudian di handleTapAction Anda bisa mendapatkan indexPath seperti ini:

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

}
DvixExtract
sumber
1

Swift 4 dan 5

Metode 1 menggunakan delegasi protokol

Misalnya, Anda memiliki UITableViewCelldengan namaMyCell

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

Sekarang buat file protocol

protocol MyCellDelegate {
    func didPressButton(cell: UITableViewCell)
}

Langkah selanjutnya, buat Ekstensi UITableView

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

Dalam UIViewControllermenerapkan protokol AndaMyCellDelegate

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

Metode 2 menggunakan penutupan

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

Catatan: - jika Anda ingin mendapatkan UICollectionViewindexPath Anda dapat menggunakan ini UICollectionView extensiondan ulangi langkah-langkah di atas

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

Di Swift 3. Juga menggunakan pernyataan penjaga, menghindari kawat gigi yang panjang.

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

    print(indexPath)
}
Sean
sumber
Ini tidak akan berhasil. Superview tombol tidak akan menjadi sel.
rmaddy
Ini berhasil. Satu-satunya hal yang harus Anda perhatikan adalah tumpukan tampilan setiap orang berbeda. Bisa jadi sender.superview, sender.superview.superview atau sender.superview.superview.superview. Tapi itu bekerja dengan sangat baik.
Sean
0

Terkadang tombol mungkin berada di dalam tampilan lain UITableViewCell. Dalam hal ini superview.superview mungkin tidak memberikan objek sel dan karenanya indexPath akan menjadi nihil.

Dalam hal ini kita harus terus mencari superview sampai kita mendapatkan objek selnya.

Berfungsi untuk mendapatkan objek sel melalui superview

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
}

Sekarang kita bisa mendapatkan indexPath dengan menekan tombol seperti di bawah ini

@IBAction func tapButton(_ sender: UIButton)
{
    let cell = getCellForView(view: sender)
    let indexPath = myTabelView.indexPath(for: cell)
}
Teena nath Paul
sumber
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)
    }

}
iAleksandr
sumber