요소가 활성화되었을 때 indexpath.row를 가져오는 방법은 무엇입니까?
버튼이 있는 테이블 뷰가 있는데 그 중 하나를 누르면 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)
}
조르아슈크는 거의 그의 대답과 함께 참을 뻔했지만, 그는 셀이 여분을 가지고 있다는 사실을 간과했습니다.contentView
레이어. 따라서 한 레이어 더 깊이 들어가야 합니다.
guard let cell = sender.superview?.superview as? YourCellClassHere else {
return // or fatalError() or whatever
}
let indexPath = itemTable.indexPath(for: cell)
이는 보기 계층 내에서 테이블 보기에 셀이 하위 보기로 있고, 그 다음에는 고유한 '내용 보기'가 있기 때문에 셀 자체를 가져오려면 이 내용 보기의 수퍼뷰를 가져와야 합니다.따라서 단추가 셀의 내용 보기에 직접 포함되지 않고 하위 보기에 포함된 경우, 단추에 액세스하려면 몇 개의 계층을 더 깊이 이동해야 합니다.
위의 접근법이 그러한 접근법 중 하나이지만 반드시 최선의 접근법은 아닙니다.기능적이지만, 다음과 같은 세부 사항을 가정합니다.UITableViewCell
애플은 뷰 계층과 같은 문서화된 적이 없습니다.이것은 나중에 변경될 수 있으며, 위의 코드는 결과적으로 예측할 수 없는 동작을 할 수 있습니다.
위와 같은 이유로 수명과 신뢰성을 고려하여 다른 접근 방식을 채택할 것을 권장합니다.이 스레드에는 여러 가지 대안이 나열되어 있으며, 이를 읽어 보시기를 권장합니다. 하지만 개인적으로 가장 좋아하는 것은 다음과 같습니다.
셀 클래스에서 닫힘 속성을 보유하고 단추의 작업 메서드가 이 속성을 호출하도록 합니다.
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
논쟁. 된 것보다 입니다. 되지 않은 특성에입니다.이것은 문서화되지 않은 특성에 의존하지 않기 때문에 위에 나열된 접근 방식보다 훨씬 안전합니다.
이러한 문제에 대한 저의 접근 방식은 셀과 테이블 보기 사이에 위임 프로토콜을 사용하는 것입니다.이렇게 하면 버튼 핸들러를 셀 하위 클래스에 유지할 수 있으며, 이를 통해 버튼 핸들러 로직을 뷰 컨트롤러에 유지하면서 인터페이스 빌더의 프로토타입 셀에 터치업 작업 핸들러를 할당할 수 있습니다.
또한 보기 계층을 탐색하거나 사용하는 잠재적으로 취약한 접근 방식을 방지합니다.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)")
}
}
업데이트: 버튼(섹션과 행 모두)이 포함된 셀의 indexPath 가져오기:
버튼 위치 사용
의 buttonTapped
메서드는 버튼의 위치를 잡고 테이블 뷰에서 좌표로 변환한 다음 해당 좌표에 있는 행의 indexPath를 가져올 수 있습니다.
func buttonTapped(_ sender:AnyObject) {
let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
}
참고: 기능을 사용할 때 가장자리 케이스에 부딪힐 수 있습니다.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 Tree에 오르는 것보다 위에서 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
}
저는 슈퍼뷰 트리에서 스윙하는 것이 앱을 설계하는 위험한 방법일 수 있다는 것을 알았기 때문에 이 방법을 선호합니다.또한 목표-C를 위해 저는 과거에 이 기술을 사용했고 그 결과에 만족했습니다.
UITableView 확장을 사용하여 보기가 포함된 셀을 가져옵니다.
@테이블 보기에 메시지를 보내는 대리자 속성을 사용하여 사용자 지정 셀 유형을 설정하는 것에 대한 Paulw11의 답변은 좋은 방법이지만 설정하는 데 일정한 작업이 필요합니다.
셀을 찾는 테이블 뷰 셀의 뷰 계층 구조를 걷는 것은 좋지 않은 생각이라고 생각합니다.취약합니다. 나중에 레이아웃 목적으로 보기에 단추를 포함하면 코드가 손상될 수 있습니다.
보기 태그를 사용하는 것도 취약합니다.셀을 만들 때 태그를 설정해야 하며, 다른 목적으로 뷰 태그를 사용하는 뷰 컨트롤러에서 해당 접근 방식을 사용하면 태그 번호가 중복되어 코드가 예상대로 작동하지 않을 수 있습니다.
테이블 뷰 셀에 포함된 모든 뷰에 대한 indexPath를 가져올 수 있는 UITableView 확장을 만들었습니다.다음을 반환합니다.Optional
전달된 뷰가 실제로 테이블 뷰 셀에 포함되지 않는 경우 이 값은 0이 됩니다.아래는 확장 소스 파일 전체입니다.에 이 된 파일을 .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에서 위의 확장자를 사용하는 작업 데모 프로젝트를 다운로드할 수 있습니다.테이블 보기확장 .git
솔루션:
셀에 단추(myButton) 또는 다른 보기가 있습니다.다음과 같이 cellForRowAt에 태그 할당
cell.myButton.tag = indexPath.row
이제 Function(기능) 또는 다른 기능을 누릅니다.이렇게 가져와서 로컬 변수에 저장합니다.
currentCellNumber = (sender.view?.tag)!
그런 다음 현재 셀 번호를 사용하여 선택한 버튼의 indexPath.row를 가져올 수 있습니다.
맛있게 드세요!
위해서Swift2.1
방법을 찾았어요 도움이 될 거예요
let point = tableView.convertPoint(CGPoint.zero, fromView: sender)
guard let indexPath = tableView.indexPathForRowAtPoint(point) else {
fatalError("can't find point in tableView")
}
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
}
}
매우 간단한 인덱스 경로 스위프트 4, 5
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! Cell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonTapped:", forControlEvents:
UIControlEvents.TouchUpInside)
Btn 내부의 IndexPath를 가져오는 방법 클릭
func buttonTapped(_ sender: UIButton) {
print(sender.tag)
}
이벤트 핸들러의 발신자는 버튼 그 자체이기 때문에 버튼의tag
덱스를속성, 화됨초에서 됩니다.cellForRowAtIndexPath
.
하지만 조금만 더 일을 한다면 저는 완전히 다른 방법으로 할 것입니다.사용자 지정 셀을 사용하는 경우 다음과 같이 문제에 접근합니다.
- 사용자 지정 테이블 셀에 'indexPath' 속성 추가
- 그을초합 다니화기것으로 합니다.
cellForRowAtIndexPath
- 탭 핸들러를 보기 컨트롤러에서 셀 구현으로 이동
- 위임 패턴을 사용하여 보기 컨트롤러에 탭 이벤트에 대해 알림, 인덱스 경로 전달
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.
}
스위프트 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
}
}
convertPoint 메서드를 사용하여 테이블 뷰에서 포인트를 가져오고 이 포인트를 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);
}
}
}
#selector를 사용하여 IBaction을 호출해 보십시오.인덱스 경로의 행에 대한 셀에서
cell.editButton.tag = indexPath.row
cell.editButton.addTarget(self, action: #selector(editButtonPressed), for: .touchUpInside)
이렇게 하면 editButtonPressed 메서드 내의 인덱스 경로에 액세스할 수 있습니다.
func editButtonPressed(_ sender: UIButton) {
print(sender.tag)//this value will be same as indexpath.row
}
파티에 좀 늦은 것 같은데, 재미있는 코드를 가져왔어요.
셀에서 버튼 탭을 처리하는 방법
또는 하위 클래스에서 버튼 탭을 처리하기 위해 위에서 다루는 패턴을 두 가지 모두에 대해 약간의 우려 사항이 분리되도록 제안합니다.cell
리고그고.viewController
.
셀의 indexPath를 찾는 방법
그러나 다른 이유로 인해 버튼이나 내부의 다른 UIView 하위 클래스를 누를 때 셀을 찾아야 한다면 클래스 확장을 사용할 것을 제안합니다.이렇게 하면 인터페이스 분리를 달성하고 코드를 약간 솔리드화할 수 있습니다.
다른 솔루션의 문제:
태그: 위에서 제안한 대로 행을 삽입하거나 삭제할 때 태그가 깨지기 쉽습니다.
superView 속성 사용:그것은 결코 깔끔하지 않습니다.다음 단계에 도달하려면 몇 개의 뷰 계층을 통과해야 합니까?
cell
하는 그자체또그포는것하함을것는것▁itselfaining.tableView
당신의 코드에 아름답지 않은 이런 것이 나타날 수도 있습니다.let tableView = view.superView.superView.superView.superView
제가 제안하는 것:
첫번째
에 확장자 UIResponder
superView
상당한view
T
뷰 계층 구조에서.
extension UIResponder {
func next<T: UIResponder>(_ type: T.Type) -> T? {
self.next as? T ?? self.next?.next(type)
}
}
이렇게 하면 지정된 유형의 보기 또는 계층의 끝에서 0을 반환할 보기를 찾을 때까지 전체 보기 계층 구조가 반복됩니다.
다음 분.
확장자를 작성하고 방법을 사용하여 셀이 속한 위치와indexPath
감방의
extension UITableViewCell {
var tableView: UITableView? {
return next(UITableView.self)
}
var indexPath: IndexPath? {
return tableView?.indexPathForRow(at: self.center)
//return tableView?.indexPath(for: self) // Note: This will return nil if the cell is not visible yet
}
}
바로 그겁니다.깔끔하고 심플합니다.
당신이 원하는 곳에 이렇게 사용하세요.
func buttonTapped(_ sender: UIButton) {
guard let cell = sender.next(YourCellType.self), let indexPath = cell.indexPath else {
return
}
// Use indexPath here
}
스위프트 3에서.또한 긴 중괄호 체인을 피하면서 가드 문을 사용했습니다.
func buttonTapped(sender: UIButton) {
guard let cellInAction = sender.superview as? UITableViewCell else { return }
guard let indexPath = tableView?.indexPath(for: cellInAction) else { return }
print(indexPath)
}
때때로 버튼이 UITableViewCell의 다른 보기 안에 있을 수 있습니다.그런 경우의 개요.superview는 셀 개체를 제공하지 않을 수 있으므로 indexPath는 0이 됩니다.
그렇다면 우리는 세포 객체를 얻을 때까지 계속해서 수퍼뷰를 찾아야 합니다.
셀 객체를 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
}
이제 아래와 같이 버튼을 누르면 indexPath를 얻을 수 있습니다.
@IBAction func tapButton(_ sender: UIButton)
{
let cell = getCellForView(view: sender)
let indexPath = myTabelView.indexPath(for: cell)
}
저의 경우 섹션이 여러 개 있고 섹션과 행 인덱스가 모두 중요하기 때문에 이러한 경우에는 UIButton에 cell 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
}
그런 다음 핸들TapAction에서 다음과 같은 indexPath를 얻을 수 있습니다.
@objc func handleTapAction(_ sender: UIButton) {
self.selectedIndex = sender.indexPath
}
// 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)
}
}
UITableView를 확장하여 보기에 대한 인덱스 경로를 가져오는 함수를 만듭니다.
extension UITableView {
func indexPath(for view: UIView) -> IndexPath? {
self.indexPathForRow(at: view.convert(.zero, to: self))
}
}
사용 방법:
let row = tableView.indexPath(for: sender)?.row
행 및 횡단에 단일 태그 사용
행/항목과 TableView/CollectionView 섹션을 동시에 전송하기 위해 태그를 사용하는 간단한 방법이 있습니다.
cellForRowAt에서 UIView.tag에 대한 IndexPath 인코딩인덱스 경로:
buttonForCell.tag = convertIndexPathToTag(with: indexPath)
대상 셀렉터의 송신기에서 IndexPath를 디코딩합니다.
@IBAction func touchUpInsideButton(sender: UIButton, forEvent event: UIEvent) {
var indexPathForButton = convertTagToIndexPath(from: sender)
}
인코더 및 디코더:
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비트 장치에 4294967296 행/항목 이상이 필요하지 않은 경우;-).
- 42949 섹션 100_000개 항목/행
- 1_000_000개 항목/행이 있는 4294개 섹션 - (위 예제와 동일)
- 10_000_000개 항목/행이 있는 429개 섹션
—-
경고: TableView/CollectionView에서 행/항목을 삭제하거나 삽입할 때 버튼의 태그 번호를 모델과 동기화하기 위해 삽입/삭제 지점 이후에 모든 행/항목을 다시 로드해야 합니다.
—-
언급URL : https://stackoverflow.com/questions/28659845/how-to-get-the-indexpath-row-when-an-element-is-activated
'programing' 카테고리의 다른 글
Ruby로부터 Python 배우기; 차이점과 유사점 (0) | 2023.06.05 |
---|---|
Firebase 사용자 테이블에 추가 세부 정보 추가 (0) | 2023.06.05 |
CSS에서 다중 변환을 적용하는 방법은 무엇입니까? (0) | 2023.05.31 |
Capybara 2.0으로 업그레이드한 후 항목 목록에서 첫 번째 링크를 클릭하는 방법은 무엇입니까? (0) | 2023.05.31 |
iPhone 5 CSS 미디어 쿼리 (0) | 2023.05.31 |