从 UICollectionViewCell 中删除单元格和相应的图像?

Delete cell and the corresponding image from UICollectionViewCell?

我有一个带有自定义 UICollectionViewCell 的水平 UICollectionView。每个单元格都有一个 UIImageView 显示用户选择的图像。 现在,我想要做的是在每个单元格的角落添加一个删除按钮(或图像?),当它被点击时,它会从数组和单元格本身中删除相应的图像。我有 2 个问题:

  1. 如何以编程方式添加 button/image 功能(我真的不想弄乱故事板)
  2. 如何实现对应UIViewController的删除功能?

像这样:

这是我的自定义单元格 class:

class PhotoCell: UICollectionViewCell, UIGestureRecognizerDelegate
{
    @IBOutlet weak var cellImage: UIImageView!

    override func awakeFromNib()
    {
        super.awakeFromNib()
        setupUI()
    }

    func setupUI()
    {
        cellImage.layer.cornerRadius = 5
        cellImage.clipsToBounds = true
        cellImage.contentMode = .scaleAspectFill
    }
}

下面是整个视图控制器的代码

   import UIKit
    import SDWebImage
    import Photos
    import AssetsPickerViewController
    import SVProgressHUD

    class PhotoVC: UIViewController
    {
        // MARK: IBOutlets
        @IBOutlet weak var collectionView: UICollectionView!
        @IBOutlet weak var postButton: UIButton!
        @IBOutlet weak var userProfileImage: UIImageView!
        @IBOutlet weak var userUsername: UsernameLabel!
        @IBOutlet weak var postTitleTextField: UITextField!
        @IBOutlet weak var postContentTextField: UITextView!
        @IBOutlet weak var postTagsTextField: UITextField!
        @IBOutlet weak var postSourceTextField: UITextField!

        // MARK: Class Properties
        var user: UserModel!
        var post: Post!
        var cameraPhotoUIImage: UIImage?
        var assets = [PHAsset]()
        lazy var assetsTurnedIntoImages =
        {
            return  [UIImage]()
        }()

        lazy var imageManager = {
            return PHCachingImageManager()
        }()

        // MARK: View Did Load
        override func viewDidLoad()
        {
            self.assetsTurnedIntoImages = [UIImage](repeating: UIImage(), count: assets.count) // Important! make sure to have enough pre-created space in the array
            super.viewDidLoad()
            setupCollectionView()
        }

        // MARK: View Did Appear
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            fetchUserUsernameAndProfileImage()
            userProfileImageSetup()
            handlePostButtonState()
            collectionView.reloadData()
        }

        // MARK: View Will Disappear
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            emptyArrays()
         }

        // MARK: Fetch User Username And Profile Photo
        func fetchUserUsernameAndProfileImage()
        {
            Api.User.observeCurrentUser
            { (userModel) in
                self.user = userModel
                self.userUsername.text = userModel.username_lowercase!
                if let userProfileImageURL = URL(string: userModel.profileImageUrlString!)
                {
                    self.userProfileImage.sd_setImage(with: userProfileImageURL, placeholderImage: UIImage(named: "default_profileHeader"))
                }
            }
        }

        // MARK: Cancel Pressed
        @IBAction func cancelPressed(_ sender: UIButton)
        {
            emptyArrays()
            collectionView.reloadData()
            dismiss(animated: true, completion: nil)
        }

        // MARK: Post Pressed
        @IBAction func postPressed(_ sender: UIButton)
        {
            guard let title = postTitleTextField.text else { return }
            guard let content = postContentTextField.text else { return }
            guard let tags = postTagsTextField.text else { return }
            guard let source = postSourceTextField.text else { return }

            view.endEditing(true)
            SVProgressHUD.setDefaultMaskType(.gradient)
            SVProgressHUD.show(withStatus: "Posting...")
            print("Assets turned into images before posting is:", assetsTurnedIntoImages.count)
            if let takenImage = cameraPhotoUIImage
            {
                let imageToUpload = takenImage

                if let imageData = UIImageJPEGRepresentation(imageToUpload, 0.1)
                {
                    let ratio: [CGFloat] = [imageToUpload.size.width / imageToUpload.size.height]
                    DatabaseService.uploadDataToServer(data: imageData, videoUrl: nil, multipleImages: nil, ratio: ratio, title: title, content: content, tags: tags, source: source,
                                                       onSuccess:
                                                       {
                                                            self.clean()
                                                            self.performSegue(withIdentifier: Segue_PhotoPostToTabbar, sender: nil)
                                                       })
                }
            }
            else if assetsTurnedIntoImages.count > 0
            {
                DatabaseService.uploadDataToServer(data: nil, videoUrl: nil, multipleImages: assetsTurnedIntoImages, ratio: nil, title: title, content: title, tags: tags, source: source,
                                                   onSuccess:
                                                   {
                                                    self.clean()
                                                    self.performSegue(withIdentifier: Segue_PhotoPostToTabbar, sender: nil)
                                                   })
            }
            else
            {
                SVProgressHUD.showError(withStatus: "At least 1 photo is required to make this post.")
            }
        }

        @IBAction func settingsPressed(_ sender: UIButton)
        {
            //TODO: Work on settings for the post
        }

        // MARK: End Editing
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
        {
            view.endEditing(true)
        }

        // MARK: Clean Text Fields And Arrays
        func clean()
        {
            postTitleTextField.text = ""
            postTagsTextField.text = ""
            postContentTextField.text = ""
            postSourceTextField.text = ""
            emptyArrays()
        }

        // MARK: Empty Arrays
        func emptyArrays()
        {
            assets.removeAll()
            assetsTurnedIntoImages.removeAll()
            cameraPhotoUIImage = nil
            collectionView.reloadData()
        }

        // MARK: Handle Post Button State
        func handlePostButtonState()
        {
            if cameraPhotoUIImage != nil || assets.count > 0
            {
                postButton.isEnabled = true
            }
            else
            {
                postButton.isEnabled = false
            }
        }

        // MARK: User Profile UI Update
        func userProfileImageSetup()
        {
            userProfileImage.layer.cornerRadius = userProfileImage.frame.size.width / 2
            userProfileImage.clipsToBounds = true
        }

    }

    // MARK: Collectionew View Delegate & Datasourse
    extension PhotoVC : UICollectionViewDataSource, UICollectionViewDelegate
    {
        func setupCollectionView()
        {
            collectionView.dataSource = self
            collectionView.delegate = self
        }

        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
        {
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoPostCVCell", for: indexPath) as! PhotoPostCVCell
                if let takenImage = cameraPhotoUIImage
                {
                    cell.cellImage.image = takenImage
                }
                if assets.count > 0
                {
                    let asset = assets[indexPath.row]

                    var imageRequestOptions: PHImageRequestOptions
                    {
                        let options = PHImageRequestOptions()
                        options.version = .current
                        options.resizeMode = .exact
                        options.deliveryMode = .fastFormat
                        options.isSynchronous = true
                        return options
                    }
                    // TODO: Fix the size of the images. Right now it's 500x500
                    let targetSize = CGSize(width: 500, height: 500)
                    imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: imageRequestOptions)
                    { (image, info) in
                        if image != nil
                        {
                            print(image!.size)
                            cell.cellImage.image = image
                            self.assetsTurnedIntoImages[indexPath.row] = image!
                            cell.deleteButton?.tag = indexPath.row
                            cell.deleteButton?.addTarget(self, action: #selector(self.deleteImage(sender:)), for: UIControlEvents.touchUpInside)
                        }
                    }
                }
                return cell
        }

        @objc func deleteImage(sender:UIButton) {
            let i = sender.tag
            print(i)
            assetsTurnedIntoImages.remove(at: i)
            collectionView.reloadData()
        }

        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
        {
            if assetsTurnedIntoImages.count > 0
            {
                return assetsTurnedIntoImages.count
            }
            else
            {
                return 1
            }
        }

        // MARK: Preview Selected Image
        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
        {
            let postStoryboard = UIStoryboard(name: Storyboard_Post, bundle:nil)

            if let destinationVC = postStoryboard.instantiateViewController(withIdentifier: "PreviewImageVC") as? PreviewImageVC
            {
                destinationVC.allowedDismissDirection = .both
                destinationVC.maskType = .clear
                if cameraPhotoUIImage != nil
                {
                    destinationVC.transferedImageToPreview = cameraPhotoUIImage!
                    destinationVC.showInteractive()
                }
                if assetsTurnedIntoImages.count > 0
                {
                    destinationVC.transferedImageToPreview = assetsTurnedIntoImages[indexPath.row]
                    destinationVC.showInteractive()
                }

            }
        }
    }

你好,这里有两个 classes 作为演示(请原谅懒惰的代码)

    import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var myCollectionView: UICollectionView!
    var dataForDemo = [0,1,2,3,4,5,6,7,8,9,10]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dataForDemo.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCollectionCell", for: indexPath) as! MyCollectionCell
        cell.myTitlteLabel.text = String(dataForDemo[indexPath.item])

        cell.callback = callbackForCell() // option callback
//        cell.buttonX.tag = indexPath.item  // option button tag
        return cell
    }

    func callbackForCell() -> ((MyCollectionCell)->Void){ // option callback
        return { [weak self] cell in
            guard let `self` = self else { return }
            guard let index = self.myCollectionView.indexPath(for: cell) else { return }

            self.dataForDemo.remove(at: index.item)
            self.myCollectionView.reloadData()
        }
    }

    @IBAction func buttonAction(_ sender: UIButton) { // option button tag
//        self.dataForDemo.remove(at: sender.tag)
//        self.myCollectionView.reloadData()
    }

}

和单元格 class:

class MyCollectionCell: UICollectionViewCell {

    var callback : ((MyCollectionCell)->Void)?  // option callback
    @IBOutlet weak var buttonX: UIButton!   // option button tag
    @IBOutlet weak var myTitlteLabel: UILabel!
    @IBAction func removeButtonAction(_ sender: Any) {
        callback?(self)
    }
}

情节提要如下所示:

因此,这里有两种方法供您选择。一个是回调,另一个是按钮上的标签。

我个人更喜欢带有回调块的那个。

这很容易实现。在左上角的单元格 xib 中添加一个 UIButton,它仅与图像视图部分重叠。添加约束。然后将此按钮的插座连接到您的电池 class:称其为 deleteButton.

您可以将情节提要中的按钮图像设置为此图像:https://i.stack.imgur.com/lGpjY.png。

那么代码可以如下:

class CustomCell: UICollectionViewCell {
 
    @IBOutlet weak var deleteButton: UIButton!
    
}

并且在集合视图控制器中:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as? CustomCell else { return UICollectionViewCell() }
    cell.deleteButton?.tag = indexPath.row
    cell.deleteButton?.addTarget(self, action: #selector(deleteUser(sender:)), for: UIControlEvents.touchUpInside)
    // Do other cell setup here with data source
    return cell
}

@objc func deleteUser(sender:UIButton) {
    let i = sender.tag
    dataSource.remove(at: i)
    collectionView.reloadData()
}

此处,dataSource 是用于填充每个单元格的模型数组。

希望对您有所帮助。