使用委托将照片导入特定的 tableview 单元格
use delegate to import photo to specific tableview cell
我希望我的 swift 代码使用委托将照片从照片库导入特定的 table 视图单元格。现在正在发生的事情是照片被导入到总是去第一个单元格。因此,如果用户单击第二个单元格中的导入按钮,照片应该转到第二个单元格。标签不起作用。如果可能,我想使用委托。
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)
}
}
问题:
selectedIndexPath = IndexPath(row: 0, section: 0)
addCeller
方法中的硬编码 indexPath 值
解法:
您需要对代码进行一些重构。
1. 在单元格本身中捕获按钮选择器,因此您可以 return / 将 self 作为参数传递给协议方法。这不是一个非常理想的解决方案(因为您只对索引路径感兴趣而不是单元格本身,但我不太清楚您在 returning 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:
正如 OP 在下面的评论中提到的,这些修改导致了编译错误,因为我已经修改了协议方法声明并且没有在答案中更新它,因此编辑以反映相同的内容。
protocol CustomTvCellDelegateadd: AnyObject {
func addCeller(_ customTV: CustomTv)
}
正如我已经在下面的评论中解释的那样,我不确定方法中位置参数的目的(如果它只是为了传达此解决方案不再需要的所选单元格的索引)因此我省略了导致编译错误的声明参数:)
我希望我的 swift 代码使用委托将照片从照片库导入特定的 table 视图单元格。现在正在发生的事情是照片被导入到总是去第一个单元格。因此,如果用户单击第二个单元格中的导入按钮,照片应该转到第二个单元格。标签不起作用。如果可能,我想使用委托。
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)
}
}
问题:
selectedIndexPath = IndexPath(row: 0, section: 0)
addCeller
方法中的硬编码 indexPath 值
解法:
您需要对代码进行一些重构。
1. 在单元格本身中捕获按钮选择器,因此您可以 return / 将 self 作为参数传递给协议方法。这不是一个非常理想的解决方案(因为您只对索引路径感兴趣而不是单元格本身,但我不太清楚您在 returning 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:
正如 OP 在下面的评论中提到的,这些修改导致了编译错误,因为我已经修改了协议方法声明并且没有在答案中更新它,因此编辑以反映相同的内容。
protocol CustomTvCellDelegateadd: AnyObject {
func addCeller(_ customTV: CustomTv)
}
正如我已经在下面的评论中解释的那样,我不确定方法中位置参数的目的(如果它只是为了传达此解决方案不再需要的所选单元格的索引)因此我省略了导致编译错误的声明参数:)