从 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
从 uiviewcontroller 操作 uicollectionviewcell 内的 uicollectionview
为啥我的 UICollectionViewCell 没有从 UICollectionViewController 获取数据?