使用委托将照片导入特定的 tableview 单元格

Posted

技术标签:

【中文标题】使用委托将照片导入特定的 tableview 单元格【英文标题】:use delegate to import photo to specific tableview cell 【发布时间】:2021-04-17 02:02:52 【问题描述】:

我希望我的 swift 代码使用委托将照片从照片库导入特定的表格视图单元格。现在发生的事情是将照片导入到始终进入第一个单元格。因此,如果用户单击第二个单元格中的导入按钮,照片应该转到第二个单元格。标签不工作。如果可能,我想使用委托。

import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,CustomTvCellDelegateadd, UIImagePickerControllerDelegate & UINavigationControllerDelegate 
    @objc func addCeller(_ customTV: CustomTv, location: CGPoint) 
        selectedIndexPath = IndexPath(row: 0, section: 0)
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary
        present(imagePicker, animated: true, completion: nil)
        
      
    
    
   
    var cellCount = 5
    var tableview = UITableView()
    var selectedIndexPath = IndexPath(row: 0, section: 0)


    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) 
        guard let selectedImage = info[.originalImage] as? UIImage else 
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        
        guard let cell = tableview.cellForRow(at: selectedIndexPath) as? CustomTv else  return 
        cell.pic.image = selectedImage
        tableview.reloadData()
        
        dismiss(animated: true, completion: nil)
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return cellCount // use a variable here so you can change it as you delete cells, else it will crash
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 118
    
   
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTv
        cell.addd.tag = indexPath.row
        cell.delegatef = self
     
    
      cell.addd.addTarget(self, action: #selector(addCeller), for: .touchDown)
        return cell
    
    

 
    
    override func viewDidLoad() 
        super.viewDidLoad()

        tableview.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height * 0.8)
        
        
        view.addSubview(tableview)

 
        tableview.register(CustomTv.self, forCellReuseIdentifier: "cell")
        tableview.delegate = self
        tableview.dataSource = self
      
    
    


// you need to declare a cell delegate that will let your tableview know when the button was tapped on the cell


protocol CustomTvCellDelegateadd: AnyObject 
    func addCeller(_ customTV: CustomTv, location: CGPoint)

class CustomTv: UITableViewCell  // it's good form to Pascal case your class name ;)
    
    
    weak var delegatef: CustomTvCellDelegateadd?
    lazy var backView : UIView = 
        let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width  , height: 110))
        view.backgroundColor = .green
        
        return view
    ()


    
    lazy var addd : UIButton = 
        let btn = UIButton(frame: CGRect(x: 250-25, y: 0, width: 100 , height: 55))
        btn.backgroundColor = .brown
        btn.setTitle("Add", for: .normal)
        btn.titleLabel?.textAlignment = .center
        return btn
        
    ()


        lazy var pic : UIImageView = 
            let btn = UIImageView(frame: CGRect(x: 50-25, y: 6, width: 100 , height: 110))
            btn.backgroundColor = .systemPink
    
            return btn
    
        ()
 
   
    override func layoutSubviews() 
        backView.clipsToBounds = true
        backView.frame =  CGRect(x: 0, y: 6, width: bounds.maxX  , height: 110)
        
        // moved these calls here instead of on setSelected(_selected:animated:)
        addSubview(backView)

        backView.addSubview(addd)
   
        backView.addSubview(pic)
        
        

        
 
      
    
    


【问题讨论】:

【参考方案1】:

问题:

selectedIndexPath = IndexPath(row: 0, section: 0)

addCeller 方法中的硬编码 indexPath 值

解决方案:

您需要对代码进行一些重组。

1. 捕获单元格本身中的按钮选择器,因此您可以将 self 作为参数返回/传递给协议方法。这不是一个非常理想的解决方案(因为您只对索引路径而不是单元格本身感兴趣,但我不太清楚您在返回 CustomTv 作为协议方法中的争论背后的想法,所以我只是保持更改与那个决定)

class CustomTv: UITableViewCell  // it's good form to Pascal case your class name ;)
    weak var delegatef: CustomTvCellDelegateadd?
    lazy var backView : UIView = 
        let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width  , height: 110))
        view.backgroundColor = .green

        return view
    ()



    lazy var addd : UIButton = 
        let btn = UIButton(frame: CGRect(x: 250-25, y: 0, width: 100 , height: 55))
        btn.backgroundColor = .brown
        btn.setTitle("Add", for: .normal)
        btn.titleLabel?.textAlignment = .center
        btn.addTarget(self, action: #selector(addButtonTapped), for: .touchUpInside)
        return btn
    ()


    lazy var pic : UIImageView = 
        let btn = UIImageView(frame: CGRect(x: 50-25, y: 6, width: 100 , height: 110))
        btn.backgroundColor = .systemPink

        return btn

    ()


    override func layoutSubviews() 
        backView.clipsToBounds = true
        backView.frame =  CGRect(x: 0, y: 6, width: bounds.maxX  , height: 110)

        // moved these calls here instead of on setSelected(_selected:animated:)
        addSubview(backView)

        backView.addSubview(addd)

        backView.addSubview(pic)
    

    @objc func addButtonTapped() 
        self.delegatef?.addCeller(self)
    

2. 现在您已将CustomTv 实例作为方法调用的一部分,通过询问tableView 直接获取索引路径

func addCeller(_ customTV: CustomTv) 
        if let indexPath = self.tableview.indexPath(for: customTV) 
            selectedIndexPath = indexPath
        
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = .photoLibrary
        present(imagePicker, animated: true, completion: nil)

3. 现在您已经设置了按钮目标,从cellForRowAtIndexPath中删除语句

cell.addd.addTarget(self, action: #selector(addCeller), for: .touchDown)

编辑 1:

正如下面 cmets 中提到的 OP,这些修改导致编译错误,因为我修改了协议方法声明并且没有在答案中更新它,因此编辑以反映相同。

protocol CustomTvCellDelegateadd: AnyObject 
    func addCeller(_ customTV: CustomTv)

正如我在下面的 cmets 中已经解释的那样,我不确定方法中 location 参数的目的(如果它只是为了传达此解决方案不再需要的所选单元格的索引),因此我省略了声明中导致编译错误的参数:)

【讨论】:

感谢您的回复,我完成了您上面列出的一切。我收到 2 个编译错误。类视图控制器出现 1 个错误,希望我添加协议存根,另一个错误在 @objc func addButtonTapped() self.delegatef?.addCeller(self) 声明调用中参数“位置”的参数缺失 @sam-burns :哦,对不起,我也更改了协议方法声明,我不确定位置是什么以及它是如何使用的,所以我删除了它,如果你使用位置来查找索引,反正你不需要它,让我用修改后的协议声明更新答案 @sam-burns:你现在能检查一下吗

以上是关于使用委托将照片导入特定的 tableview 单元格的主要内容,如果未能解决你的问题,请参考以下文章

由于 tableView 的委托实现而导致的遗留单元格布局[关闭]

通过 CoreData 和委托在静态 tableView 单元格之间传递变量

如何使用基于字段值选择的异构委托制作 QtQuick TableView / TreeView

如何将uicollectionview单元格合并到tableview第一个单元格上

在嵌套环境中点击 childviewcontroller 中的单元格访问父级父级视图控制器的 tableview 委托

tableView:didEndEditingRowAtIndexPath: 委托方法调用了两次