将 IndexPath 行值传递给委托函数而不是 Sender.tag 以删除图像项目 CollectionView Swift

Pass IndexPath row value to delegate function instead of Sender.tag to delete Image item CollectionView Swift

我正在使用 collectionView 来显示照片并委托函数来查看自定义警报。 在照片上,我有用于删除照片的十字标记。我的委托功能和显示项目都工作正常。 但是当我必须从服务器中删除照片时,我遇到了问题。因为我需要将准确的图像 ID 传递给 Web 服务以将其从服务器中删除。如果我使用 cell.tag 它给我的行值是 1 但实际 imgID 是 40992。我如何将这个值传递给我的删除委托函数?

结构:

单元格项目显示 --tap gesture call removeImage func --- custom alert -- on Delete button -- didDeleteButtonClicked called.

我在 cellForItem 中需要的主要价值:

let imgId = AppData?.imageList?[indexPath.row].projectUnitImageId

PhotoViewController:

public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellName, for: indexPath) as! PhotoCollectionViewCell

            if(indexPath.row < (AppData?.imageList?.count ?? 0)){
                cell.imageView.isHidden = false
                cell.closeIcon.isHidden = false
                cell.addIcon.isHidden = true
                let dic = AppData?.imageList?[indexPath.row].url ?? " "
                cell.imageView.image =  UIImage(url: URL(string: dic))


                let imgId = AppData?.imageList?[indexPath.row].projectUnitImageId
                print(imgId)

                cell.closeIcon.isUserInteractionEnabled = true
                cell.closeIcon.tag = imgId ?? 0
                deleteAlertView.delegate = self
                let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(removeImage(_:)))
                cell.closeIcon.addGestureRecognizer(tapGestureRecognizer)

            } else {
                cell.imageView.isHidden = true
                cell.closeIcon.isHidden = true
                cell.addIcon.isHidden = false
            }

            return cell
        }


        @objc func removeImage(_ sender: AnyObject){

            print(imgId)
            let fotoXib = Bundle.main.loadNibNamed("FotoDeleteAlert", owner: self, options: nil)
            let alertView = fotoXib?.first as! FotoDeleteAlert
            alertView.delegate = self
            self.view.addSubview(alertView)

        }


          //MARK: - Delegate Function

extension PhotoCollectionViewController: handleDeleteAction {

        func didDeleteButtonClicked(_ sender: UIButton) {

            print("delegate")
            let row = sender.tag
            print(row)

            // I have to call my delete webServices here and have to pass imgId
            deleteWebservices(imgId)


        }
    }

FotoAlert Xib 自定义提醒:

protocol handleDeleteAction {
    func didDeleteButtonClicked(_: UIButton)
}

@IBDesignable class FotoDeleteAlert: UIView {

    var delegate: handleDeleteAction?

    @IBOutlet weak var deleteBtn: UIButton!

    override func awakeFromNib() {
        super.awakeFromNib()
        layoutIfNeeded()
        deleteBtn.addTarget(self, action: #selector(didDelete(_:)), for: .touchUpInside)
    }

    @IBAction func didCancel(_ sender: Any) {
        removeFromSuperview()
    }

    @IBAction func didDelete(_ sender: UIButton) {

        self.delegate?.didDeleteButtonClicked(sender)
        removeFromSuperview()


    }
}

你需要

guard let id = AppData?.imageList?[row].projectUnitImageId else { return }  
deleteWebservices(id)

标签是查找与用户交互的特定单元格的一种脆弱方式。相反,我建议使用按钮的坐标。

我写了一个答案给这个主题:

在那个答案中,我写了一个 UITableView 的扩展,indexPathForView(_:) 该函数接受一个视图(包含在 table 视图单元格中)并且returns 包含该视图的单元格的索引路径。

您可以对集合视图使用完全相同的方法。 Table 视图具有函数 indexPathForRow(at:),集合视图具有等效函数 indexPathForItem(at:)

UI集合视图的扩展看起来像这样:(未测试)

import UIKit

public extension UICollectionView {

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

        //The center of the view is a better point to use, but we can only use it if the view has a superview
        guard let superview = view.superview else {
            //The view we were passed does not have a valid superview.
            //Use the view's bounds.origin and convert from the view's coordinate system
            let origin = self.convert(view.bounds.origin, from: view)
            let indexPath = self.indexPathForItem(at: origin)
            return indexPath
        }
        let viewCenter = self.convert(center, from: superview)
        let indexPath = self.indexPathForItem(at: viewCenter)
        return indexPath
    }
}

重构您的 FotoDeleteAlert 以获得 imgID 属性。让其 didDeleteButtonClicked 方法传回图像 ID,而不是点击的按钮:

protocol handleDeleteAction {
    func didDeleteButtonClickedForImageID(_: Integer)
}

然后您需要重写您的 removeImage(_:) 函数以获取手势识别器并使用它来查找 IndexPath:

    @objc func removeImage(_ tapper: UIGetstureRecognizer) {
        //Find the view associated with the tap gesture recognizer
        guard let view = tapper.view, 
        //use the view to find the indexPath of the cell
        let indexPath = collectionView. indexPathForView(view) else { 
            return 
        }
        let imgId = AppData?.imageList[indexPath.row].projectUnitImageId
        let fotoXib = Bundle.main.loadNibNamed("FotoDeleteAlert", owner: self, options: nil)
        let alertView = fotoXib?.first as! FotoDeleteAlert
        alertView.delegate = self

        //Pass the image ID to the FotoDeleteAlert
        alertView.imgID = imgID
        self.view.addSubview(alertView)
    }

然后在 FotoDeleteAlert 的删除处理程序中,您可以获取图像 ID 并使用它向您的服务器发出删除命令。

TL;DR;

您设置了 cell.closeIcon 的标签,但随后您使用了 FotoDeleteAlert 按钮的标签。

要解决这个问题,您需要添加


class FotoDeleteAlert: ... {
   ...

   func setButtonTag(imageId: Int) {
       button.tag = imageId
   }
}


 @objc func removeImage(_ sender: UIView){

    print(imgId)
    let fotoXib = Bundle.main.loadNibNamed("FotoDeleteAlert", owner: self, options: nil)
    let alertView = fotoXib?.first as! FotoDeleteAlert
    alertView.setButtonTag(imageId: sender.tag
    alertView.delegate = self
    self.view.addSubview(alertView)
}


extension PhotoCollectionViewController: handleDeleteAction {

        func didDeleteButtonClicked(_ sender: UIButton) {

            print("delegate")
            let imgId = sender.tag


            // I have to call my delete webServices here and have to pass imgId
            deleteWebservices(imgId)


        }
    }

现在让我们清理你的意大利面条代码

你的大部分 collectionView(_:, cellForItemAt: ) 都可以移到 PhotoCollectionViewCell 中。 我不会通过 tag 发送 id,相反你可以创建自己的委托

最后我会把它改写成这样:

class Controller {
    func displayAlert(for info: PhotoInfo) {
        // I bet this code is invalid (view isn't correctly aligned

        let fotoXib = Bundle.main.loadNibNamed("FotoDeleteAlert", owner: self, options: nil)
        let alertView = fotoXib?.first as! FotoDeleteAlert
        alertView.delegate = self
        self.view.addSubview(alertView)
    }
}

extension Controller: UICollectionViewDelegate {
    func collectionView(
        _ collectionView: UICollectionView, 
        cellForItemAt indexPath: IndexPath
    ) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: cellName, for: indexPath
        ) as! PhotoCollectionViewCell

        let imgInfo: PhotoInfo? = AppData?.imageList?[indexPath.row]
        cell.display(info: imgInfo)
        cell.delegate = self

        return cell
    }
}

extension Controller: PhotoCollectionViewCellDelegate {
    func photoCollectionViewCell(didPressCloseBtn cell: PhotoCollectionViewCell) {
        guard let indexPath = collectionView.indexPath(for: cell) else { return }
        if let imgInfo: PhotoInfo = AppData?.imageList?[indexPath.row] {
            displayAlert(for: imgInfo)
        }
    }
}

extension Controller: FotoDeleteAlertDelegate {
    func fotoDeleteAlert(
        didPressDelete view: FotoDeleteAlert, for item: PhotoInfo?
    ) {
        guard let item: PhotoInfo = item else { return }
        deleteWebservices(item.projectUnitImageId)
    }

}

protocol PhotoCollectionViewCellDelegate: class {
    func photoCollectionViewCell(didPressCloseBtn: PhotoCollectionViewCell)
}

class PhotoCollectionViewCell: UICollectionViewCell {
    weak var delegate: PhotoCollectionViewCellDelegate?

    var closeIcon: UIButton! {
        didSet {
            button.addTarget(
                self, action: #selector(closeTap), for: .touchUpInside
            )
        }
    }


    func display(info: PhotoInfo?) {
        imageView.isHidden = info == nil
        closeIcon.isHidden = info == nil
        addIcon.isHidden = info != nil

        if let info = info {
            imageView.image =  UIImage(url: URL(string: info.url))
        }
    }

    @objc func closeTap() {
        delegate?.photoCollectionViewCell(didPressCloseBtn: self)
    }

}

protocol FotoDeleteAlertDelegate: class {
    func fotoDeleteAlert(
        didPressDelete view: FotoDeleteAlert, for item: PhotoInfo?
    )

}

class FotoDeleteAlert {
    weak var delegate: FotoDeleteAlertDelegate?

    var deleteButton: UIButton! {
        didSet {
            button.addTarget(
                self, action: #selector(deleteTap), for: .touchUpInside
            )
        }
    }

    private var item: PhotoInfo?

    func display(item: PhotoInfo) {
        self.item = item
    }

    @objc func deleteTap() {
        delegate?.fotoDeleteAlert(didPressDelete: self, for: item)
    }
}