将 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)
}
}
我正在使用 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)
}
}