web-dev-qa-db-ja.com

UITableViewCellアクション付きボタン

こんにちは、ショッピングカート機能を処理する3つのボタン、プラス、マイナス、および削除ボタンを持つカスタムUITableViewCellがあり、どのセルがタッチされたかを知る必要があります。

「タグソリューション」を使用しようとしましたが、セルのライフサイクルが原因で機能しません。

誰かが解決策を見つけるのを手伝ってくれますか?

前もって感謝します

11
jack87

UITableViewCellのサブクラス内のセルデリゲートメソッドを使用してこれを解決していました。

簡単な概要:

1)プロトコルの作成

protocol YourCellDelegate : class {
    func didPressButton(_ tag: Int)
}

2)サブクラス your UITableViewCell(まだ行っていない場合):

class YourCell : UITableViewCell
{
     var cellDelegate: YourCellDelegate?   
      @IBOutlet weak var btn: UIButton!
    // connect the button from your cell with this method
    @IBAction func buttonPressed(_ sender: UIButton) {
        cellDelegate?.didPressButton(sender.tag)
    }         
    ...
}

Letビューcontroller上記で実装されたYourCellDelegateプロトコルに準拠。

class YourViewController: ..., YourCellDelegate {  ... }

4)デリゲートを設定、セルが定義された後(再利用のため)。

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! YourCell
cell.cellDelegate = self
cell.btn.tag = indexPath.row

5)同じコントローラ(実装されているUITableViewデリゲート/データソースはどこにありますか)、YourCellDelegateプロトコルからメソッドを置く

func didPressButton(_ tag: Int) {
     print("I have pressed a button with a tag: \(tag)")
}

これで、ソリューションはタグ/番号に依存しなくなりました。必要な数のボタンを追加できるため、インストールするボタンの数に関係なく、デリゲート経由で応答を受け取る準備ができています。

このプロトコルデリゲートソリューションはiOSロジックで優先され、UISwitchUIStepperなどのテーブルセル内の他の要素に使用できます。

50
pedrouan

コミュニティから広く提案されているように、IBOutletsをプライベートにした後、同じ問題に遭遇しました。

私の解決策は次のとおりです。

<セルクラス内>

protocol YourCellDelegate: class {
    func didTapButton(_ sender: UIButton)
}

class YourCell: UITableViewCell {

    weak var delegate: YourCellDelegate?

    @IBAction func buttonTapped(_ sender: UIButton) {
        delegate?.didTapButton(sender)
    }
}

<ViewControllerで>

class ViewController: UIViewController, YourCellDelegate {

    func didTapButton(_ sender: UIButton) {
        if let indexPath = getCurrentCellIndexPath(sender) {
            item = items[indexPath.row]
        }
    }

    func getCurrentCellIndexPath(_ sender: UIButton) -> IndexPath? {
        let buttonPosition = sender.convert(CGPoint.zero, to: tableView)
        if let indexPath: IndexPath = tableView.indexPathForRow(at: buttonPosition) {
            return indexPath
        }
        return nil
    }
}
15
Frederico

Swift 4。*

それは次のようにもできます。多くのコーディングと委任は不要で、シンプルで簡単です。

cellForItemAtの場合はUICollectionViewに、またはcellForRowAtの場合はUITableViewに次のコードを配置します

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

そして、あなたの方法は

@objc func buttonSelected(sender: UIButton){
    print(sender.tag)
}

それで全部です。

8
Abhishek Mitra

@pedrouanは、ボタンのtagオプションを使用する以外は素晴らしいです。多くの場合、tableViewCellにボタンを設定すると、それらのボタンはtableView dataSourceを変更します(例:InsertRow、DeleteRow)。

ただし、新しいセルがinsertedまたはdeletedであっても、ボタンのタグは更新されません。したがって、ボタンのcellをパラメーターに渡すのではなく、tag自体をパラメーターとして渡すことをお勧めします。

これを実現するための例を次に示します。

あなたのExampleCell

protocol ExampleCellDelegate: class {
    func didTapButton(cell: ExampleCell)
}

class ExampleCell: UITableViewCell {

    weak var cellDelegate: ExampleCellDelegate?

    @IBAction func btnTapped(_ sender: UIButton) {
        cellDelegate?.didTapButton(cell: self)
    }
}

あなたのViewController

class ViewController: ExampleCellDelegate {
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as? ExampleCell {

            cell.cellDelegate = self
            return cell
        }
        return UITableViewCell()
    }

    func didTapButton(cell: ExampleCell) {
        if let indexPath = tableView.indexPath(for: cell) {
            // do Something
        }
    }
}
3
Changnam Hong

Swift 4.2

デリゲートの代わりにクロージャーを使用することもできます

1)UITableViewCellで:

 class ExampleCell: UITableViewCell {
    //create your closure here  
         var buttonPressed : (() -> ()) = {}

        @IBAction func buttonAction(_ sender: UIButton) {
    //Call your closure here 
            buttonPressed()
        }
    }

2)ViewControllerで

class ViewController:  UIViewController,  UITableViewDataSource, UITableViewDelegate {
 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleCell", for: indexPath) as! ExampleCell
   cell.buttonPressed = {
          //Code
           }
return cell 
  }
}
3
RimK

TableViewCellビューの階層を使用して、選択したボタンのインデックスを取得することもできます。

次の手順を使用します。

  1. tableviewのcellForRowAtIndexpathにセレクターを追加します。

    btn?.addTarget(self, action:#selector(buttonPressed(_:)), for:.touchUpInside)
    

2。次のメソッドを使用してindexPathを取得します。

func buttonPressed(_ sender: AnyObject) {
        let button = sender as? UIButton
        let cell = button?.superview?.superview as? UITableViewCell
        let indexPath = tblview.indexPath(for: cell!)
        print(indexPath?.row)
    }
3
KKRocks

TableviewセルのUIButton。プログラムでSwift 4.2のアクションメソッドを作成します

cell.btnlike.addTarget(self, action: #selector(buttonbtnlikePressed(_:event:)), for: .touchUpInside)


@objc func buttonbtnlikePressed(_ sender: Any, event: Any) {
        let point : CGPoint = (sender as AnyObject).convert(CGPoint.zero, to:tblPost)
        var indexPath =  self.tblPost!.indexPathForRow(at: point)
        if let btnlike = sender as? UIButton{
            if btnlike.isSelected{
                btnlike.isSelected = false
            }else{
                btnlike.isSelected = true
            }
        }
    }
1