Làm thế nào để lấy indexpath.row khi một phần tử được kích hoạt?


104

Tôi có một chế độ xem bảng với các nút và tôi muốn sử dụng indexpath.row khi một trong số chúng được nhấn. Đây là những gì tôi hiện có, nhưng nó luôn là 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)
}

tôi có nên sử dụng IndexPathForSelectedRow () thay vì biến điểm không? hoặc tôi nên sử dụng nó ở đâu?
Vincent

Câu trả lời:


164

giorashc gần như đã có nó với câu trả lời của mình, nhưng anh ấy đã bỏ qua thực tế là tế bào có thêm một contentViewlớp. Vì vậy, chúng ta phải đi sâu hơn một lớp:

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

let indexPath = itemTable.indexPath(for: cell)

Điều này là do trong hệ thống phân cấp chế độ xem, một tableView có các ô là các chế độ xem phụ mà sau đó có 'chế độ xem nội dung' của riêng chúng, đây là lý do tại sao bạn phải lấy chế độ xem siêu cao của chế độ xem nội dung này để lấy chính ô đó. Do đó, nếu nút của bạn nằm trong chế độ xem phụ thay vì trực tiếp vào chế độ xem nội dung của ô, bạn sẽ phải đi sâu hơn nhiều lớp để truy cập nó.

Trên đây là một trong những cách tiếp cận như vậy, nhưng không nhất thiết là cách tiếp cận tốt nhất. Trong khi nó hoạt động, nó giả định các chi tiết về mộtUITableViewCell mà Apple chưa bao giờ nhất thiết phải ghi lại, chẳng hạn như hệ thống phân cấp chế độ xem. Điều này có thể được thay đổi trong tương lai và kết quả là đoạn mã trên có thể hoạt động không thể đoán trước được.

Kết quả của những điều trên, vì lý do tuổi thọ và độ tin cậy, tôi khuyên bạn nên áp dụng một cách tiếp cận khác. Có rất nhiều lựa chọn thay thế được liệt kê trong chủ đề này và tôi khuyến khích bạn đọc xuống, nhưng sở thích cá nhân của tôi là như sau:

Giữ một thuộc tính của một bao đóng trên lớp ô của bạn, yêu cầu phương thức hành động của nút gọi điều này.

class MyCell: UITableViewCell {
    var button: UIButton!

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

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

Sau đó, khi bạn tạo ô trong đó cellForRowAtIndexPath, bạn có thể gán một giá trị cho phần đóng của mình.

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

Bằng cách di chuyển mã trình xử lý của bạn đến đây, bạn có thể tận dụng lợi thế của indexPathđối số đã có . Đây là cách tiếp cận an toàn hơn nhiều so với cách được liệt kê ở trên vì nó không dựa trên các đặc điểm không có giấy tờ.


2
Được phát hiện tốt. Tôi là một nhà phát triển có năng lực, tôi hứa;) - Đã sửa đổi câu trả lời của tôi.
Jacob King

12
Đây không phải là cách thích hợp để lấy ô từ một nút. Bố cục của ô đã thay đổi trong nhiều năm và mã như thế này sẽ không hoạt động khi điều đó xảy ra. Không sử dụng cách tiếp cận này.
rmaddy

11
Đây là một giải pháp tồi. Nó giả định các chi tiết về UITableViewCells mà Apple chưa bao giờ nhất thiết phải đồng ý. Mặc dù UITableViewCells có thuộc tính contentView nhưng không có gì đảm bảo rằng superview của contentView sẽ luôn là Ô.
bpapa

1
@PintuRajput Bạn có thể vui lòng mô tả hệ thống phân cấp chế độ xem của bạn cho tôi được không? Bạn có thể thấy điều này vì nút của bạn không phải là một chế độ xem phụ trực tiếp của chế độ xem nội dung của ô.
Jacob King

2
@ymutlu Tôi hoàn toàn đồng ý, tôi đã nêu điều này trong câu trả lời. Tôi cũng đã đề xuất một giải pháp mạnh mẽ hơn nhiều. Lý do tôi để nguyên bản gốc là bởi vì tôi cảm thấy tốt hơn là nên cho các nhà phát triển khác thấy các vấn đề bằng một cách tiếp cận hơn là né tránh nó hoàn toàn, điều này không dạy họ những gì bạn thấy. :)
Jacob King

61

Cách tiếp cận của tôi đối với loại vấn đề này là sử dụng giao thức ủy quyền giữa ô và chế độ xem bảng. Điều này cho phép bạn giữ trình xử lý nút trong lớp con ô, cho phép bạn chỉ định trình xử lý hành động cảm ứng cho ô nguyên mẫu trong Trình tạo giao diện, trong khi vẫn giữ logic xử lý nút trong bộ điều khiển chế độ xem.

Nó cũng tránh cách tiếp cận có khả năng dễ hỏng trong việc điều hướng phân cấp chế độ xem hoặc sử dụng thuộc tagtính, vốn có vấn đề khi chỉ mục ô thay đổi (do chèn, xóa hoặc sắp xếp lại thứ tự)

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

buttonTappedlà hàm đại biểu và nằm trong bộ điều khiển chế độ xem. Trong ví dụ của tôi, someButtonTappedlà phương pháp hành động trong tế bào
Paulw11

@ paulw11 tôi có tế bào không có thành viên buttonTapped trong phương pháp này@IBAction func someButtonTapped(sender: UIButton) { self.delegate?.buttonTapped(self) }
EI Captain v2.0

1
Đây là một giải pháp khá tốt (không ở đâu tệ như hai giải pháp hiện tại với nhiều phiếu bầu hơn, sử dụng thẻ nhìn vào siêu phẩm) nhưng có vẻ như có quá nhiều mã bổ sung để thêm vào.
bpapa

2
Đây là giải pháp chính xác và phải là câu trả lời được chấp nhận. Nó không lạm dụng thuộc tính thẻ, không giả định việc xây dựng các ô (Apple có thể dễ dàng thay đổi) và sẽ vẫn hoạt động (không cần mã hóa thêm) khi các ô được di chuyển hoặc các ô mới được thêm vào giữa các ô hiện có.
Robotic Cat

1
@ Paulw11 Ban đầu tôi nghĩ rằng đây là rất nhiều mã, nhưng nó đã được chứng minh là linh hoạt hơn rất nhiều so với những gì tôi đang sử dụng trước đây. Cảm ơn bạn đã đăng giải pháp mạnh mẽ này.
Adrian

53

CẬP NHẬT : Lấy đường dẫn chỉ mục của ô chứa nút (cả phần và hàng):

Sử dụng vị trí nút

Bên trong buttonTappedphương thức của bạn , bạn có thể lấy vị trí của nút, chuyển đổi nó thành một tọa độ trong tableView, sau đó lấy indexPath của hàng tại tọa độ đó.

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

LƯU Ý : Đôi khi bạn có thể gặp trường hợp cạnh khi sử dụng hàm view.convert(CGPointZero, to:self.tableView)dẫn đến việc tìm kiếm nilmột hàng tại một điểm, mặc dù có một ô tableView ở đó. Để khắc phục điều này, hãy thử chuyển một tọa độ thực hơi lệch so với gốc, chẳng hạn như:

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

Câu trả lời trước: Sử dụng Thuộc tính thẻ (chỉ trả về hàng)

Thay vì trèo vào cây superview để lấy con trỏ đến ô chứa UIButton, có một kỹ thuật an toàn hơn, có thể lặp lại nhiều hơn bằng cách sử dụng thuộc tính button.tag được Antonio đề cập ở trên, được mô tả trong câu trả lời này và được hiển thị bên dưới:

Trong cellForRowAtIndexPath:bạn đặt thuộc tính thẻ:

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

Sau đó, trong buttonClicked:hàm, bạn tham chiếu thẻ đó để lấy hàng của indexPath nơi đặt nút:

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

Tôi thích phương pháp này hơn vì tôi nhận thấy rằng đu dây trong các cây siêu quan sát có thể là một cách mạo hiểm để thiết kế một ứng dụng. Ngoài ra, đối với mục tiêu-C, tôi đã sử dụng kỹ thuật này trong quá khứ và rất hài lòng với kết quả.


5
Đây là một cách làm hay và tôi sẽ ủng hộ nó để giúp đại diện của bạn bắt đầu một chút, tuy nhiên, lỗ hổng duy nhất là nó không cấp quyền truy cập vào indexPath.section nếu điều này cũng cần thiết. Câu trả lời tuyệt vời mặc dù!
Jacob King

Cảm ơn Jacob! Tôi đánh giá cao nghiệp đại diện. Nếu bạn muốn nhận phần indexPath.sectionbổ sung indexPath.row(mà không cần đặt lại thuộc tính thẻ as indexPath.section), cellForRowAtIndexPath:bạn chỉ cần thay đổi thẻ thành button.tag = indexPathvà sau đó trong buttonClicked:hàm, bạn có thể truy cập cả hai bằng cách sử dụng sender.tag.rowsender.tag.section.
Iron John Bonney

1
Đây có phải là một tính năng mới không, vì tôi chắc rằng tôi nhớ thuộc tính thẻ là loại Int chứ không phải loại AnyObject, trừ khi điều đó thay đổi trong nhanh chóng 2.3?
Jacob King

@JacobKing bạn nói đúng! Thật tệ là tôi đã hoàn toàn giãn cách khi viết nhận xét đó và nghĩ rằng thẻ đó là loại AnyObject. Derp - đừng bận tâm đến tôi. Sẽ rất hữu ích nếu bạn có thể chuyển indexPath dưới dạng thẻ ...
Iron John Bonney

3
Cũng không hẳn là một cách tiếp cận tốt. Đối với một điều, nó sẽ chỉ hoạt động trong Chế độ xem bảng nơi có một phần duy nhất.
bpapa

16

Sử dụng tiện ích mở rộng cho UITableView để tìm nạp ô cho bất kỳ chế độ xem nào:


Câu trả lời của @ Paulw11 về việc thiết lập loại ô tùy chỉnh với thuộc tính ủy quyền gửi thông báo đến chế độ xem bảng là một cách tốt để thực hiện, nhưng nó đòi hỏi một lượng công việc nhất định để thiết lập.

Tôi nghĩ rằng việc đi bộ trong bảng phân cấp chế độ xem của ô để tìm ô là một ý tưởng tồi. Nó rất dễ vỡ - nếu sau này bạn đặt nút của mình trong một khung nhìn cho mục đích bố cục, thì mã đó có khả năng bị hỏng.

Việc sử dụng thẻ xem cũng rất mong manh. Bạn phải nhớ thiết lập các thẻ khi tạo ô và nếu bạn sử dụng phương pháp đó trong bộ điều khiển chế độ xem sử dụng thẻ chế độ xem cho mục đích khác, bạn có thể có số thẻ trùng lặp và mã của bạn có thể không hoạt động như mong đợi.

Tôi đã tạo một tiện ích mở rộng cho UITableView cho phép bạn lấy indexPath cho bất kỳ chế độ xem nào được chứa trong ô chế độ xem bảng. Nó trả về một giá trị Optionalsẽ là nil nếu chế độ xem được truyền vào thực sự không nằm trong ô chế độ xem bảng. Dưới đây là toàn bộ tệp nguồn mở rộng. Bạn có thể chỉ cần đặt tệp này vào dự án của mình và sau đó sử dụng indexPathForView(_:)phương thức được bao gồm để tìm đường dẫn chỉ mục chứa bất kỳ chế độ xem nào.

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

Để sử dụng nó, bạn có thể chỉ cần gọi phương thức trong IBAction cho một nút được chứa trong một ô:

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

(Lưu ý rằng indexPathForView(_:)hàm sẽ chỉ hoạt động nếu đối tượng dạng xem mà nó truyền vào được chứa bởi một ô hiện đang ở trên màn hình. Điều đó hợp lý, vì dạng xem không có trên màn hình không thực sự thuộc về một đường dẫn chỉ mục cụ thể; nó có khả năng được gán cho một đường dẫn chỉ mục khác khi nó chứa ô được tái chế.)

BIÊN TẬP:

Bạn có thể tải xuống một dự án demo đang hoạt động sử dụng tiện ích mở rộng trên từ Github: TableViewExtension.git


Cảm ơn Tôi đã sử dụng tiện ích mở rộng để lấy indexPath của một textview trong một ô - hoạt động hoàn hảo.
Jeremy Andrews

9

Đối với Swift2.1

Tôi đã tìm thấy một cách để làm điều đó, hy vọng, nó sẽ hữu ích.

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

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

Nó có nghĩa là gì nếu lỗi chạy? Một số lý do khiến nó không thể tìm thấy điểm trong tableView là gì?
OOProg

Điều này (hoặc tương tự, bằng cách sử dụng các phương pháp Chuyển đổi UIView) phải là câu trả lời được chấp nhận. Không chắc tại sao nó hiện là # 4, vì nó không đưa ra giả định về hệ thống riêng tư của chế độ xem bảng, nó không sử dụng thuộc tính thẻ (hầu như luôn luôn là một ý tưởng tồi) và không liên quan đến nhiều mã bổ sung.
bpapa

9

Giải pháp Swift 4:

Bạn có một nút (myButton) hoặc bất kỳ chế độ xem nào khác trong ô. Gán thẻ trong cellForRowAt như thế này

cell.myButton.tag = indexPath.row

Bây giờ bạn chạm vào Chức năng hoặc bất kỳ chức năng nào khác. Tìm nạp nó như thế này và lưu nó trong một biến cục bộ.

currentCellNumber = (sender.view?.tag)!

Sau đó, bạn có thể sử dụng currentCellNumber ở bất kỳ đâu để lấy indexPath.row của nút đã chọn.

Thưởng thức!


Cách tiếp cận đó hoạt động, nhưng các thẻ lượt xem rất mỏng manh, như đã đề cập trong câu trả lời của tôi. Ví dụ: một thẻ số nguyên đơn giản sẽ không hoạt động đối với chế độ xem bảng phân đoạn. (một IndexPath nó 2 số nguyên.) Cách tiếp cận của tôi sẽ luôn hoạt động và không cần cài đặt thẻ vào nút (hoặc chế độ xem có thể áp dụng khác.)
Duncan C

6

Trong Swift 4, chỉ cần sử dụng cái này:

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

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

Câu trả lời rõ ràng nhất, nên được chọn. Chỉ có điều cần lưu ý là đó tableViewlà một biến đầu ra cần được tham chiếu trước trước khi câu trả lời này hoạt động.
10000RubyPools,

Làm việc như say mê !!
Parthpatel1105

4

Rất đơn giản để có được Đường dẫn chỉ mục nhanh chóng 4, 5

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


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

Cách lấy IndexPath Inside Btn Click:

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


}

3

Vì người gửi của trình xử lý sự kiện là chính nút, tôi muốn sử dụng thuộc tính của nút tagđể lưu trữ chỉ mục, được khởi tạo trongcellForRowAtIndexPath .

Nhưng với một chút công việc nữa, tôi sẽ làm theo một cách hoàn toàn khác. Nếu bạn đang sử dụng một ô tùy chỉnh, đây là cách tôi sẽ tiếp cận vấn đề:

  • thêm thuộc tính 'indexPath` vào ô bảng tùy chỉnh
  • khởi tạo nó trong cellForRowAtIndexPath
  • di chuyển trình xử lý chạm từ bộ điều khiển chế độ xem sang triển khai ô
  • sử dụng mẫu ủy quyền để thông báo cho bộ điều khiển chế độ xem về sự kiện chạm, chuyển đường dẫn chỉ mục

Antonio, tôi có một ô tùy chỉnh và rất muốn làm theo cách của bạn. Tuy nhiên, nó không hoạt động. Tôi muốn chạy mã 'vuốt để hiển thị nút xóa', đó là phương thức tableView commitE Chỉnh sửaStyle. Tôi đã xóa mã đó khỏi lớp mainVC và đặt nó vào lớp customCell, nhưng bây giờ mã không còn hoạt động nữa. Tôi đang thiếu gì?
Dave G

Tôi nghĩ rằng đây là cách tốt nhất để có được những indexPath của một tế bào với các bộ phận x, tuy nhiên tôi không thấy sự cần thiết của các gạch đầu dòng 3 và 4 trong một cách tiếp cận MVC
Edward

2

Sau khi thấy đề xuất của Paulw11 về việc sử dụng một cuộc gọi lại ủy quyền, tôi muốn giải thích một chút về nó / đưa ra một đề xuất khác, tương tự. Nếu bạn không muốn sử dụng mẫu đại biểu, bạn có thể sử dụng các đóng nhanh chóng như sau:

Lớp tế bào của bạn:

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

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

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

cellForRowAtIndexPathPhương pháp của bạn :

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

Tôi đã tìm thấy một cách rất dễ sử dụng để quản lý bất kỳ ô nào trong tableView và collectionView bằng cách sử dụng lớp Model và điều này hoạt động hoàn hảo.

Thực sự có một cách tốt hơn nhiều để xử lý điều này bây giờ. Điều này sẽ hoạt động để quản lý ô và giá trị.

Đây là đầu ra của tôi (ảnh chụp màn hình), vì vậy hãy xem điều này:

nhập mô tả hình ảnh ở đây

  1. Rất đơn giản để tạo lớp mô hình , vui lòng làm theo quy trình dưới đây. Tạo lớp nhanh với tên RNCheckedModel, viết mã như bên dưới.
class RNCheckedModel: NSObject {

    var is_check = false
    var user_name = ""

    }
  1. tạo lớp tế bào của bạn
class InviteCell: UITableViewCell {

    @IBOutlet var imgProfileImage: UIImageView!
    @IBOutlet var btnCheck: UIButton!
    @IBOutlet var lblName: UILabel!
    @IBOutlet var lblEmail: UILabel!
    }
  1. và cuối cùng sử dụng lớp mô hình trong UIViewController của bạn khi bạn sử dụng UITableView của mình .
    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

Tôi đã sử dụng phương thức convertPoint để lấy điểm từ chế độ xem bảng và chuyển điểm này đến phương thức indexPathForRowAtPoint để lấy 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);
            }   
        }
    }

1

Hãy thử sử dụng #selector để gọi IBaction. Trong cellforrowatindexpath

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

Bằng cách này, bạn có thể truy cập đường dẫn chỉ mục bên trong phương thức editButtonPressed

func editButtonPressed(_ sender: UIButton) {

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

}

Câu trả lời thích hợp nhất
Amalendu Kar

Không, thẻ sẽ tắt khi người dùng thêm hoặc xóa ô.
koen

1

Trong trường hợp của tôi, tôi có nhiều phần và cả chỉ mục phần và hàng đều quan trọng, vì vậy trong trường hợp đó, tôi chỉ tạo một thuộc tính trên UIButton mà tôi đặt đường dẫn chỉ mục ô như vậy:

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

Sau đó, đặt thuộc tính trong cellForRowAt như thế này:

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

Sau đó, trong handleTapAction, bạn có thể lấy indexPath như sau:

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

}

1

Swift 4 và 5

Phương pháp 1 sử dụng đại biểu giao thức

Ví dụ, bạn có một UITableViewCellvới tênMyCell

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

Bây giờ tạo một protocol

protocol MyCellDelegate {
    func didPressButton(cell: UITableViewCell)
}

Bước tiếp theo, tạo một Tiện ích mở rộng của UITableView

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

Trong UIViewControllerviệc triển khai giao thức của bạnMyCellDelegate

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

Phương pháp 2 sử dụng bao đóng

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

Lưu ý: - nếu bạn muốn lấy UICollectionViewindexPath, bạn có thể sử dụng điều này UICollectionView extensionvà lặp lại các bước trên

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

0

Trong Swift 3. Cũng sử dụng các câu lệnh bảo vệ, tránh một chuỗi dài các dấu ngoặc nhọn.

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

    print(indexPath)
}

Điều này sẽ không hoạt động. Superview của nút sẽ không phải là ô.
rmaddy

Điều này có hiệu quả. Điều duy nhất bạn nên cẩn thận là mức độ xem của mọi người là khác nhau. Đó có thể là sender.superview, sender.superview.superview hoặc sender.superview.superview.superview. Nhưng nó hoạt động thực sự tốt.
Sean

0

Đôi khi nút có thể nằm bên trong một chế độ xem khác của UITableViewCell. Trong trường hợp đó superview.superview có thể không cung cấp đối tượng ô và do đó indexPath sẽ bằng không.

Trong trường hợp đó, chúng ta nên tiếp tục tìm superview cho đến khi chúng ta nhận được đối tượng cell.

Hàm lấy đối tượng ô bằng 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
}

Bây giờ chúng ta có thể lấy indexPath trên nút nhấn như bên dưới

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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.