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

Posted

技术标签:

【中文标题】从 UICollectionViewCell 中删除单元格和相应的图像?【英文标题】:Delete cell and the corresponding image from UICollectionViewCell? 【发布时间】:2017-09-21 13:00:05 【问题描述】:

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

    如何以编程方式添加按钮/图像功能(我真的不想弄乱情节提要) 如何实现对应UIViewController的删除功能?

类似这样的:

这是我的自定义单元类:

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
    

这是整个View Controller的代码

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

            
        
    

【问题讨论】:

如果你有CollectionView,那么你可以通过storyboard或xib轻松管理,只需获取一组imageView并通过collectionView管理它(_collectionView:UICollectionView,numberOfItemsInSection section:Int) 当我没有真正的按钮时,这将无济于事。我还提到我也不知道该怎么做 【参考方案1】:

这很容易实现。将UIButton 添加到左上角的单元格xib 中,该单元格仅与您的图像视图部分重叠。添加约束。然后将此按钮的插座连接到您的单元类:将其命名为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 是用于填充每个单元格的模型数组。

我希望这会有所帮助。

【讨论】:

我正在测试您的代码,但我看到的问题是,当我尝试删除某些内容时,它总是删除数组中的最后一项(图像),而不是选定的索引。另外,如果我删除数组中的所有项目,它基本上会超出范围并崩溃 @Dani 好的。用不同的方法编辑了答案。请让我知道这对你有没有用。 :) 啊,还在做同样的事情。我也尝试过cell.deleteButton?.tag = indexPath.row - 1,但这还不算接近。我不确定为什么它不起作用。它从字面上删除了数组的最后一项,而不是选定的一项。无论您点击哪个单元格的删除按钮(无论是第一个还是中间某处,总是删除最后一项) 在deleteUser函数中添加断点,此时sender.tag是什么? 你的数据源是什么?一个数组?【参考方案2】:

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

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

故事板如下所示:

所以这里有两个关于如何执行此操作的选项。一个是回调,另一个是按钮上的标签。

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

【讨论】:

我也测试了你的方法。我获得了与上面 Pravan 建议的结果相同的结果。出于某种原因,回调方法和 button.tag 都不适合我。它总是删除数组的最后一项,不管你点击哪个删除按钮

以上是关于从 UICollectionViewCell 中删除单元格和相应的图像?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 UICollectionViewCell 呈现 AlertView

从 UICollectionViewCell 转为失败?

从 uiviewcontroller 操作 uicollectionviewcell 内的 uicollectionview

为啥我的 UICollectionViewCell 没有从 UICollectionViewController 获取数据?

1144: 零起点学算法51——数组中删数

从 XIB 加载时 UICollectionViewCell 导致崩溃