요소가 활성화되었을 때 indexpath.row를 얻는 방법은 무엇입니까?


104

버튼이있는 테이블 뷰가 있고 그중 하나를 탭하면 indexpath.row를 사용하고 싶습니다. 이것은 내가 현재 가지고 있지만 항상 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)
}

포인트 변수 대신 IndexPathForSelectedRow ()를 사용해야합니까? 또는 어디에서 사용해야합니까?
빈센트

답변:


164

giorashc는 그의 대답으로 거의 그것을 가지고 있었지만, 그는 세포에 여분의 contentView층 이 있다는 사실을 간과했습니다 . 따라서 우리는 한 층 더 깊이 가야합니다.

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

let indexPath = itemTable.indexPath(for: cell)

이는 뷰 계층 구조 내에서 tableView가 자체 '컨텐츠 뷰'를 갖는 하위 뷰로 셀을 가지고 있기 때문에 셀 자체를 가져 오려면이 콘텐츠 뷰의 수퍼 뷰를 가져와야합니다. 결과적으로 버튼이 셀의 콘텐츠보기에 직접 들어가는 것이 아니라 하위보기에 포함되어있는 경우 액세스하려면 더 많은 레이어로 이동해야합니다.

위의 방법은 이러한 접근 방식 중 하나이지만 반드시 최선의 접근 방식은 아닙니다. 기능적이지만 UITableViewCell뷰 계층 구조와 같이 Apple이 반드시 문서화하지 않은 에 대한 세부 정보를 가정 합니다. 이는 향후 변경 될 수 있으며 결과적으로 위의 코드가 예상치 않게 작동 할 수 있습니다.

위의 결과로 수명과 신뢰성을 위해 다른 접근 방식을 채택하는 것이 좋습니다. 이 스레드에는 여러 가지 대안이 나열되어 있으며 읽어보실 것을 권장하지만 개인적으로 가장 좋아하는 것은 다음과 같습니다.

셀 클래스에 클로저 속성을 유지하고 버튼의 액션 메서드가이를 호출하도록합니다.

class MyCell: UITableViewCell {
    var button: UIButton!

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

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

그런 다음에서 셀을 만들 때 cellForRowAtIndexPath클로저에 값을 할당 할 수 있습니다.

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

여기로 핸들러 코드를 이동하면 이미 존재하는 indexPath인수를 활용할 수 있습니다 . 이것은 문서화되지 않은 특성에 의존하지 않기 때문에 위에 나열된 것보다 훨씬 안전한 접근 방식입니다.


2
잘 발견되었습니다. 나는 유능한 개발자입니다. 약속합니다.;)-내 대답을 수정했습니다.
Jacob King

12
이것은 버튼에서 셀을 가져 오는 적절한 방법이 아닙니다. 셀의 레이아웃은 수년에 걸쳐 변경되었으며 이와 같은 코드는 작동하지 않습니다. 이 방법을 사용하지 마십시오.
rmaddy

11
이것은 나쁜 해결책입니다. Apple이 반드시 동의하지 않은 UITableViewCell에 대한 세부 정보를 가정합니다. UITableViewCells에는 contentView 속성이 있지만 contentView의 수퍼 뷰가 항상 Cell이라는 보장은 없습니다.
bpapa

1
@PintuRajput보기 계층 구조를 설명해 주시겠습니까? 버튼이 셀 콘텐츠보기의 직접적인 하위보기가 아니기 때문에이 메시지가 표시 될 수 있습니다.
Jacob King

2
@ymutlu 나는 전적으로 동의하며 대답에 이것을 명시했습니다. 또한 훨씬 더 강력한 솔루션을 제안했습니다. 내가 원본을 그대로 두는 이유는 다른 개발자들에게 접근 방식으로 문제를 모두 피하는 것보다 보여주는 것이 더 낫다고 생각하기 때문입니다. :)
Jacob King

61

이런 종류의 문제에 대한 나의 접근 방식은 셀과 테이블 뷰 사이에 위임 프로토콜을 사용하는 것입니다. 이를 통해 버튼 핸들러를 셀 서브 클래스에 유지할 수 있습니다.이를 통해 터치 업 액션 핸들러를 인터페이스 빌더의 프로토 타입 셀에 할당하는 동시에 뷰 컨트롤러에서 버튼 핸들러 로직을 유지할 수 있습니다.

또한 tag셀 인덱스가 변경 될 때 (삽입, 삭제 또는 재정렬로 인해) 문제가 발생 하는 뷰 계층 구조를 탐색하거나 속성을 사용하는 잠재적으로 취약한 접근 방식을 방지합니다.

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

buttonTapped델리게이트 함수이며 뷰 컨트롤러에 있습니다. 내 예 someButtonTapped에서 셀의 작업 방법은
Paulw11

@ paulw11 나는 셀에는이 방법 buttonTapped 회원이 없습니다 있어요@IBAction func someButtonTapped(sender: UIButton) { self.delegate?.buttonTapped(self) }
EI 캡틴 2.0

1
이것은 꽤 좋은 해결책입니다 (현재 더 많은 표를 얻은 두 사람만큼 나쁘지는 않지만 superview를보고있는 태그를 사용).
bpapa

2
이것은 올바른 해결책이며 허용되는 답변이어야합니다. 태그 속성을 남용하지 않고 셀 구성 (Apple에서 쉽게 변경할 수 있음)을 가정하지 않으며 셀을 이동하거나 기존 셀 사이에 새 셀을 추가해도 계속 작동합니다 (추가 코딩없이).
Robotic Cat

1
@ Paulw11 처음에는 이것이 많은 코드라고 생각했지만 이전에 사용했던 것보다 훨씬 더 탄력적 인 것으로 입증되었습니다. 이 강력한 솔루션을 게시 해 주셔서 감사합니다.
Adrian

53

업데이트 : 버튼이 포함 된 셀의 indexPath 가져 오기 (섹션과 행 모두) :

버튼 위치 사용

buttonTapped메서드 내 에서 버튼의 위치를 ​​잡고 tableView의 좌표로 변환 한 다음 해당 좌표에서 행의 indexPath를 가져올 수 있습니다.

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

참고 : 때로는 tableView 셀이 있더라도 함수를 사용하여 한 지점에서 행을 view.convert(CGPointZero, to:self.tableView)찾을 때 가장자리 케이스가 nil발생할 수 있습니다. 이 문제를 해결하려면 다음과 같이 원점에서 약간 오프셋 된 실제 좌표를 전달해보십시오.

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

이전 답변 : 태그 속성 사용 (행만 반환)

UIButton이있는 셀에 대한 포인터를 잡기 위해 superview 트리로 올라가는 대신, 위에 Antonio가 언급 한 button.tag 속성을 활용하는 더 안전하고 반복 가능한 기술 있습니다.

에서 cellForRowAtIndexPath:당신 태그의 속성을 설정합니다 :

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

그런 다음 buttonClicked:함수에서 해당 태그를 참조하여 버튼이있는 indexPath의 행을 가져옵니다.

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

수퍼 뷰 트리에서 스윙하는 것이 앱을 디자인하는 위험한 방법이라는 것을 알았 기 때문에이 방법을 선호합니다. 또한 Objective-C의 경우 이전 에이 기술 을 사용해 왔으며 결과에 만족했습니다.


5
이것은 그것을하는 좋은 방법이며, 당신의 담당자를 약간 시작하기 위해 그것을 upvote 할 것이지만, 유일한 결점은 이것이 필요한 경우 indexPath.section에 대한 액세스 권한을 부여하지 않는다는 것입니다. 그래도 좋은 대답!
야곱 왕

감사합니다 Jacob! 대표 카르마에 감사드립니다. 당신이 얻을 원한다면 indexPath.section받는 사람뿐만 아니라 indexPath.row(같은 태그 속성을 재설정하지 않고 indexPath.section),에 cellForRowAtIndexPath:당신은 단지에 태그를 바꿀 수 button.tag = indexPath다음에 buttonClicked:기능 당신은 사용하여 두 액세스 할 수 sender.tag.rowsender.tag.section.
Iron John Bonney

1
빠른 2.3에서 변경되지 않는 한 태그 속성이 AnyObject 유형이 아닌 Int 유형이라는 것을 기억하기 때문에 이것이 새로운 기능입니까?
Jacob King

@JacobKing 당신이 맞아요! 내 잘못은 그 주석을 쓸 때 완전히 간격을두고 태그가 AnyObject 유형이라고 생각했습니다. Derp-신경 쓰지 마세요. 당신이 ... 비록 태그로 indexPath를 전달할 수 있다면 유용 할 것
아이언 존 Bonney

3
좋은 접근 방식도 아닙니다. 한 가지는 단일 섹션이있는 테이블 뷰에서만 작동합니다.
bpapa

16

UITableView에 대한 확장을 사용하여 모든보기의 셀을 가져옵니다.


@ Paulw11의 답변은 테이블보기에 메시지를 보내는 대리자 속성을 사용하여 사용자 지정 셀 유형을 설정하는 것이 좋은 방법이지만 설정하려면 일정량의 작업이 필요합니다.

셀을 찾는 테이블 뷰 셀의 뷰 계층 구조를 걷는 것은 나쁜 생각이라고 생각합니다. 취약합니다. 나중에 레이아웃 목적으로보기에 버튼을 포함하면 해당 코드가 깨질 수 있습니다.

뷰 태그를 사용하는 것도 취약합니다. 셀을 만들 때 태그를 설정하는 것을 기억해야하며, 다른 용도로 뷰 태그를 사용하는 뷰 컨트롤러에서 해당 접근 방식을 사용하는 경우 중복 태그 번호를 가질 수 있으며 코드가 예상대로 작동하지 않을 수 있습니다.

테이블 뷰 셀에 포함 된 모든 뷰에 대한 indexPath를 가져올 수 있도록 UITableView에 대한 확장을 만들었습니다. Optional전달 된 뷰가 실제로 테이블 뷰 셀에 속하지 않으면 nil을 반환합니다 . 아래는 전체 확장 소스 파일입니다. 이 파일을 프로젝트에 넣은 다음 포함 된 indexPathForView(_:)메서드를 사용하여 뷰가 포함 된 indexPath를 찾을 수 있습니다.

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

이를 사용하려면 셀에 포함 된 버튼에 대해 IBAction에서 메서드를 호출하기 만하면됩니다.

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

(이 indexPathForView(_:)함수는 전달 된 뷰 객체가 현재 화면에있는 셀에 포함 된 경우에만 작동합니다. 화면에없는 뷰가 실제로 특정 indexPath에 속하지 않기 때문에 합리적입니다. 셀이 재활용 될 때 다른 indexPath에 할당됩니다.)

편집하다:

Github에서 위의 확장을 사용하는 작동중인 데모 프로젝트를 다운로드 할 수 있습니다. TableViewExtension.git


확장 기능을 사용하여 셀에서 textview의 indexPath를 얻었습니다. 완벽하게 작동했습니다.
Jeremy Andrews

9

에 대한 Swift2.1

나는 그것을 할 방법을 찾았습니다. 도움이 되길 바랍니다.

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

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

오류가 발생하면 무엇을 의미합니까? tableView에서 포인트를 찾을 수없는 이유는 무엇입니까?
OOProg

이것은 (또는 유사한 UIView 변환 메서드를 사용하여) 허용되는 대답이어야합니다. 테이블 뷰의 개인 계층에 대한 가정을하지 않기 때문에 현재 # 4 인 이유는 확실하지 않으며 태그 속성 (거의 항상 나쁜 생각)을 사용하지 않으며 많은 추가 코드를 포함하지 않습니다.
bpapa

9

Swift 4 솔루션 :

셀에 단추 (myButton) 또는 다른보기가 있습니다. 다음과 같이 cellForRowAt에 태그를 할당하십시오.

cell.myButton.tag = indexPath.row

이제 탭 함수 또는 기타. 이렇게 가져 와서 지역 변수에 저장하십시오.

currentCellNumber = (sender.view?.tag)!

이 후이 currentCellNumber를 사용하여 선택한 단추의 indexPath.row를 가져올 수 있습니다.

즐겨!


이 접근 방식은 작동하지만 내 대답에서 언급했듯이 뷰 태그는 취약합니다. 예를 들어, 간단한 정수 태그는 단면 테이블 뷰에서 작동하지 않습니다. (IndexPath는 2 개의 정수입니다.) 내 접근 방식은 항상 작동하며 버튼 (또는 다른 탭 가능한보기)에 태그를 설치할 필요가 없습니다.
Duncan C

6

Swift 4에서는 다음을 사용하십시오.

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

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

가장 깨끗한 답변을 선택해야합니다. 주목할 것은 tableView이 답변이 작동하기 전에 참조해야하는 콘센트 변수라는 것입니다.
10000RubyPools

매력처럼 일하세요 !!
Parthpatel1105

4

매우 간단하게 인덱스 경로를 빠르게 4, 5

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


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

Btn Click 내부 IndexPath를 얻는 방법 :

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


}

3

이벤트 핸들러의 발신자는 버튼 자체이기 때문에 버튼의 tag속성을 사용하여 cellForRowAtIndexPath.

하지만 조금 더 작업하면 완전히 다른 방식으로 할 수 있습니다. 사용자 지정 셀을 사용하는 경우 다음과 같이 문제에 접근 할 수 있습니다.

  • 사용자 정의 테이블 셀에 'indexPath'속성 추가
  • 그것을 초기화 cellForRowAtIndexPath
  • 탭 핸들러를 뷰 컨트롤러에서 셀 구현으로 이동
  • 위임 패턴을 사용하여 탭 이벤트에 대해 뷰 컨트롤러에 알리고 인덱스 경로를 전달합니다.

안토니오, 나에게는 맞춤형 셀이 있으며이 작업을 원하는 방식으로하고 싶습니다. 그러나 작동하지 않습니다. 내 '스 와이프하여 삭제 버튼 표시'코드를 실행하고 싶습니다.이 코드는 tableView commitEditingStyle 메서드입니다. mainVC 클래스에서 해당 코드를 제거하고 customCell 클래스에 넣었지만 이제 코드가 더 이상 작동하지 않습니다. 내가 무엇을 놓치고 있습니까?
Dave G

그러나 나는 내가 MVC 접근 방식에서 글 머리 기호 3, 4에 대한 필요성이 표시되지 않습니다,이 X의 섹션 셀의 indexPath를 얻을 수있는 가장 좋은 방법이라고 생각
에드워드

2

델리게이트 콜백 사용에 대한 Paulw11의 제안을 본 후, 약간 자세히 설명하거나 유사한 다른 제안을 전달하고 싶었습니다. 델리게이트 패턴을 사용하지 않으려면 다음과 같이 신속하게 클로저를 사용할 수 있습니다.

세포 등급 :

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

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

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

귀하의 cellForRowAtIndexPath방법 :

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

Model 클래스를 사용하여 tableView 및 collectionView의 모든 셀을 관리하는 데 사용하는 매우 쉬운 방법을 찾았으며 이것은 완벽하게 작동합니다.

실제로 이것을 처리하는 훨씬 더 좋은 방법이 있습니다. 이것은 셀과 값을 관리하는 데 효과적입니다.

다음은 내 출력 (스크린 샷)이므로 다음을 참조하십시오.

여기에 이미지 설명 입력

  1. 모델 클래스 를 생성하는 것은 매우 간단 합니다. 아래 절차를 따르십시오. name으로 신속한 클래스를 RNCheckedModel만들고 아래와 같이 코드를 작성합니다.
class RNCheckedModel: NSObject {

    var is_check = false
    var user_name = ""

    }
  1. 셀 클래스 만들기
class InviteCell: UITableViewCell {

    @IBOutlet var imgProfileImage: UIImageView!
    @IBOutlet var btnCheck: UIButton!
    @IBOutlet var lblName: UILabel!
    @IBOutlet var lblEmail: UILabel!
    }
  1. 마지막으로 UITableView 를 사용할 때 UIViewController 에서 모델 클래스 를 사용하십시오 .
    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

나는 convertPoint 메소드를 사용하여 tableview에서 포인트를 얻고이 포인트를 indexPathForRowAtPoint 메소드에 전달하여 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

#selector를 사용하여 IBaction을 호출 해보십시오.

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

이렇게하면 editButtonPressed 메소드 내에서 indexpath에 액세스 할 수 있습니다.

func editButtonPressed(_ sender: UIButton) {

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

}

가장 적절한 답
Amalendu 카르

아니요, 사용자가 셀을 추가하거나 제거하면 태그가 해제됩니다.
koen

1

제 경우에는 여러 섹션이 있고 섹션과 행 인덱스가 모두 중요하므로 이러한 경우 UIButton에 속성을 생성하여 다음과 같이 셀 indexPath를 설정했습니다.

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

그런 다음 cellForRowAt에서 다음과 같이 속성을 설정하십시오.

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

그런 다음 handleTapAction에서 다음과 같이 indexPath를 얻을 수 있습니다.

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

}

1

Swift 4 및 5

프로토콜 대리자를 사용하는 방법 1

예를 들어, UITableViewCell이름이있는MyCell

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

이제 protocol

protocol MyCellDelegate {
    func didPressButton(cell: UITableViewCell)
}

다음 단계는 다음의 확장을 만듭니다. UITableView

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

당신의에서 UIViewController프로토콜을 구현MyCellDelegate

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

클로저 사용 방법 2

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

참고 : UICollectionView-indexPath 를 얻으려면 이것을 사용 UICollectionView extension하고 위의 단계를 반복 할 수 있습니다.

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

0

Swift 3에서는 긴 중괄호 체인을 피하면서 guard 문도 사용했습니다.

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

    print(indexPath)
}

작동하지 않습니다. 버튼의 수퍼 뷰는 셀이 아닙니다.
rmaddy

작동합니다. 주의해야 할 유일한 것은 모든 사람의 뷰 스택이 다르다는 것입니다. sender.superview, sender.superview.superview 또는 sender.superview.superview.superview 일 수 있습니다. 하지만 정말 잘 작동합니다.
Sean

0

때로는 버튼이 UITableViewCell의 다른 뷰 안에있을 수 있습니다. 이 경우 superview.superview는 셀 객체를 제공하지 않을 수 있으므로 indexPath는 nil이됩니다.

이 경우 셀 객체를 얻을 때까지 수퍼 뷰를 계속 찾아야합니다.

슈퍼 뷰로 셀 객체를 얻는 기능

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
}

이제 아래와 같이 버튼 탭에서 indexPath를 얻을 수 있습니다.

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

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.