Can't remove view from superview on reusable tableview cell - ios

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: EventCommentsCustom = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! EventCommentsCustom
guard let release = array[exist: indexPath.section] else { return cell }
if release.user == "condition" {
let image = UIImage()
let imageView = UIImageView(image: image)
imageView.sd_setImage(with: URL(string: "https://example.com/" + TegKeychain.get("profile_pic")!))
imageView.frame = CGRect(x: 20, y: 10, width: 50, height:50)
imageView.layer.borderWidth = 0.4
imageView.layer.masksToBounds = false
imageView.layer.borderColor = UIColor.gray.cgColor
imageView.layer.cornerRadius = 25
imageView.clipsToBounds = true
imageView.tag = 3
cell.addSubview(imageView)
let button = UIButton(frame: CGRect(x: 90, y: 10, width: 200, height: 50))
button.contentHorizontalAlignment = .left
button.setTitleColor(UIColor.lightGray, for: .normal)
button.setTitle(NSLocalizedString("Say something...", comment: ""), for: .normal)
button.addTarget(self, action: #selector(EventComments.openInput), for: .touchUpInside)
button.tag = 3
cell.addSubview(button)
} else {
if let viewWithTag = cell.viewWithTag(3) {
if viewWithTag is UIImageView {
print("DONE")
viewWithTag.removeFromSuperview()
}
}
if let viewWithTag = cell.viewWithTag(3) {
if viewWithTag is UIButton {
print("DONE")
viewWithTag.removeFromSuperview()
}
}
}
return cell
}
I am trying to remove views that I created with a tag in a reusable tableview cell.
However, I still can see UIButton and UIImageview when first reused (5. section of tableview), then It starts to remove properly
Why don't they get removed at the first reuse?

I guess that reusing in your case could mean that the image view and button get added twice for a cell. You only remove one of them though. I think you should take a different approach (like different prototype cells as #vadian stated) into consideration but for now (assuming my assumption is correct) you could try this to fix your problem:
Replace ...
if let viewWithTag = cell.viewWithTag(3) {
if viewWithTag is UIImageView {
print("DONE")
viewWithTag.removeFromSuperview()
}
}
if let viewWithTag = cell.viewWithTag(3) {
if viewWithTag is UIButton {
print("DONE")
viewWithTag.removeFromSuperview()
}
}
With ...
while let viewToRemove = cell.viewWithTag(3) {
if viewToRemove is UIImageView || viewToRemove is UIButton {
viewToRemove.removeFromSuperview()
}
}
Update -
The approach with different cell types would look something like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let release = array[exist: indexPath.section] else { return cell }
if release.user == "condition" {
let cell = tableView.dequeueReusableCell(withIdentifier: "OneIdentifier", for: indexPath) as! OneCustomCellType
// configure your cell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "AnotherIdentifier", for: indexPath) as! AnotherCustomCellType
// configure your cell
return cell
}
}

Related

when I clicked checkbox inside a tableview the amount present inside one label should add to another label in iOS

I have checkbox and label inside a tableview and when we click checkbox the price present in label in each cell of tableview should add to another label which is present in another view
#IBAction func checkUncheckButtonAction(_ sender: UIButton) {
if let cell = sender.superview?.superview as? PrepaidPageTableViewCell
{
let indexPath = tableviewOutlet.indexPath(for: cell)
if cell.checkUncheckButtonOutlet.isSelected == false
{
cell.checkUncheckButtonOutlet.setImage(#imageLiteral(resourceName: "checked_blue"), for: .normal)
cell.checkUncheckButtonOutlet.isSelected = true
viewHeightConstraint.constant = 65
cell.amountOutlet.text = "₹ "+amount_receivable_from_customerArray[indexPath!.row]
isPrepaidOrder = false
tableviewOutlet.reloadData()
} else {
cell.checkUncheckButtonOutlet.setImage(#imageLiteral(resourceName: "unchecked_blue"), for: .normal)
cell.checkUncheckButtonOutlet.isSelected = false
self.viewHeightConstraint.constant = 0
tableviewOutlet.reloadData()
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PrepaidPageTableViewCell") as! PrepaidPageTableViewCell
cell.customerNameOutlet.text = buyer_nameArray[indexPath.row]
cell.deliverydateOutlet.text = "Delivery Date:\(dispatch_dateArray[indexPath.row])"
cell.amountOutlet.text = "₹\(amount_receivable_from_customerArray[indexPath.row])"
cell.dispatchidoutlet.text = "Dispatch ID: \(id_dispatch_summaryArray[indexPath.row])"
cell.dispatchdateOutlet.text = "Dispatch Date:\(dispatch_dateArray[indexPath.row])"
cell.checkUncheckButtonOutlet.setImage(#imageLiteral(resourceName: "unchecked_blue"), for: .normal)
cell.selectionStyle = .none
return cell
}

Don't Click button inside in TableView

I have added one Button into tableview button is not clicked. The button is not clicked on the top of TableView. What should I do to make the button clickable? I need to make the CircleMenu button clickable. The button is now on top of tableView3. Do I need to add the button to the tableView?
override func viewDidLoad() {
super.viewDidLoad()
let button = CircleMenu(
frame: CGRect(x: view.frame.width/2 - 10, y: view.frame.height - 270, width: 50, height: 50),
normalIcon:"icon_menu",
selectedIcon:"icon_close",
buttonsCount: 3,
duration: 4,
distance: 85)
button.backgroundColor = UIColor.flatSkyBlue
button.delegate = self
button.layer.cornerRadius = button.frame.size.width / 2.0
view.addSubview(button)
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == self.tableView1 {
if !chipnumber2.text!.isEmpty {
let cell:DeviceTableViewCell2 = tableView1.dequeueReusableCell(withIdentifier: cellIdNew, for: indexPath) as! DeviceTableViewCell2
let deviceItem: Device3New = itemsNew[indexPath.row]
let tap1 = UITapGestureRecognizer(target: self, action: #selector(tittleNewTapped(_:)))
let tap2 = UITapGestureRecognizer(target: self, action: #selector(tittleNewTapped2(_:)))
return cell
}
}
if tableView == self.tableView2 {
if !chipnumber.text!.isEmpty {
let cell:DeviceTableViewCell2 = tableView2.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! DeviceTableViewCell2
let deviceItem: Device3 = items[indexPath.row]
cell.backgroundColor = GradientColor(UIGradientStyle.leftToRight, frame: self.view.frame, colors: [UIColor.flatPowderBlueDark, UIColor.flatSand])
return cell
}
}
if tableView == self.tableView3 {
if !chipnumber3.text!.isEmpty {
let cell:DeviceTableViewCell2 = tableView3.dequeueReusableCell(withIdentifier: cellIdNew2, for: indexPath) as! DeviceTableViewCell2
cell.backgroundColor = GradientColor(UIGradientStyle.leftToRight, frame: self.view.frame, colors: [UIColor.flatPowderBlueDark, UIColor.flatSand])
return cell
}
}
return UITableViewCell()
}
}
Just add a target to the button:
button.addTarget(self, action: #selector(buttonClicked(_:)), for: .touchUpInside)
And then a selector method:
#objc func buttonClicked(_ sender: UIButton) {
print("clicked!")
}
(Edit: Possible duplicate?)

tableview button creation dynamically in cell issue in swift

I am trying to implement dynamic button on tableview cell .i am able to add the button but as per the requirement on last cell i don't want to add button but its getting added there also as below mention screen capture
This is the requirement
my cellForRowAt indexPath code is below.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if let _ = cell {
print("cell is available")
} else {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
cell?.textLabel?.textAlignment = .left
cell?.textLabel?.text = list[indexPath.row]
let btn = UIButton(type: UIButtonType.custom) as UIButton
if cell?.textLabel?.text == "➕ Add Room" || list[indexPath.row] == "➕ Add Room"{
btn.isHidden = true
cell?.textLabel?.textAlignment = .center
}else{
btn.frame = CGRect(x: 146, y: 0, width: 20, height: (cell?.frame.height)!)
btn.addTarget(self, action: #selector(buttonPressed(sender: )), for: .touchUpInside)
btn.tag = indexPath.row
btn.setImage(UIImage(named: "delete.png"), for: .normal)
cellx = list[btn.tag]
cell?.contentView.addSubview(btn)
}
return cell!
}
and the result after this show below screen capture
i don't want to display the delete button in +Add Room row which is present in last row of table.
Please suggest me how to get the out as mention in the requirement . i made a condition for the text ("Add Room Text") to shown in centre and successfully displaying in center.
Thanks in advance please help me to solve this issue
2nd issue
in this given list if i select "COPENHAGEN " and try to delete this , its deleting the upper content means BARCELONA file gets deleted. i am not delete same seleted content from list .
It happens because UITableView reuses previously created cells. So for the last cell it takes already created cell with button inside.
It would be better to create your own subclass of UITableViewCell and use it.
But if you don't want to do that you can use this version of your code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if let cell = cell {
print("cell is available")
// Remove previously created button from reused cell view
if let button = cell.contentView.subviews.first(where: { (view: UIView) -> Bool in
view.isKind(of: UIButton.self)
}) {
button.removeFromSuperview()
}
} else {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
cell?.textLabel?.textAlignment = .left
cell?.textLabel?.text = list[indexPath.row]
if indexPath.row == (list.count - 1) {
cell?.textLabel?.textAlignment = .center
} else {
let btn = UIButton(type: UIButtonType.custom) as UIButton
btn.frame = CGRect(x: 146, y: 0, width: 20, height: (cell?.frame.height)!)
btn.addTarget(self, action: #selector(buttonPressed(sender: )), for: .touchUpInside)
btn.tag = indexPath.row
btn.setImage(UIImage(named: "delete.png"), for: .normal)
cellx = list[btn.tag]
cell?.contentView.addSubview(btn)
}
return cell!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if let _ = cell {
print("cell is available")
} else {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
}
cell?.textLabel?.textAlignment = .left
cell?.textLabel?.text = list[indexPath.row]
let btn = UIButton(type: UIButtonType.custom) as UIButton
if cell?.textLabel?.text == "➕ Add Room" || list[indexPath.row] == "➕ Add Room"{
for view in cell?.contentView.subviews as [UIView] {
if let button = view as? UIButton {
button.isHidden = true
}
}
cell?.textLabel?.textAlignment = .center
}else{
btn.frame = CGRect(x: 146, y: 0, width: 20, height: (cell?.frame.height)!)
btn.addTarget(self, action: #selector(buttonPressed(sender: )), for: .touchUpInside)
btn.tag = indexPath.row
btn.setImage(UIImage(named: "delete.png"), for: .normal)
cellx = list[btn.tag]
cell?.contentView.addSubview(btn)
}
return cell!
}
Try this. It is because of your program flow. btn instance is created for every table rows and you set hidden just the instance of the btn for last row. Table cell reused dequeue cell even though you did not add created btn into table cell content view for the latest cell. So, you need to search the button from the content view and set hidden.
Try this way
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! cell
if indexPath.row == (list.count - 1) {
btn.isHidden = true
cell?.textLabel?.textAlignment = .center
}else{
btn.isHidden = false
btn.frame = CGRect(x: 146, y: 0, width: 20, height: (cell?.frame.height)!)
btn.addTarget(self, action: #selector(buttonPressed(sender: )), for: .touchUpInside)
btn.tag = indexPath.row
btn.setImage(UIImage(named: "delete.png"), for: .normal)
cellx = list[btn.tag]
cell?.contentView.addSubview(btn)
}
I have not tested this above code just made some minor changes maybe it will work :)
If not so please let me know.
EDIT1:
Answer updated

Swift - How to change the color of an accessoryType (disclosureIndicator)?

I have question about the accessoryType of cells. I am using a cell with an disclosureIndicator as accessoryType and I want to change it's color but I can't.
Does anyone know if this is a bug or if Apple forces me to use the grey color?
Actually I can change the colors of other accessoryType.
My code looks like this:
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! customCell
cell.tintColor = UIColor.red
cell.accessoryType = .disclosureIndicator
And my arrow is still grey. But if I use a checkmark accessoryType it becomes red.
Is there any way to fix this or do I have to use a colored image?
You can do something like this
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.tintColor = UIColor.white
let image = UIImage(named: "Arrow.png")
let checkmark = UIImageView(frame:CGRect(x:0, y:0, width:(image?.size.width)!, height:(image?.size.height)!));
checkmark.image = image
cell.accessoryView = checkmark
let object = objects[indexPath.row] as! NSDate
cell.textLabel!.text = object.description
return cell
}
Sample Arrow Images
Output
Use SF Symbol
let image = UIImage(systemName: "chevron.right")
let accessory = UIImageView(frame:CGRect(x:0, y:0, width:(image?.size.width)!, height:(image?.size.height)!))
accessory.image = image
// set the color here
accessory.tintColor = UIColor.white
cell.accessoryView = accessory
Updated for Swift 4.2 with images attached:
cell.accessoryType = .disclosureIndicator
cell.tintColor = .black
let image = UIImage(named:"disclosureArrow")?.withRenderingMode(.alwaysTemplate)
if let width = image?.size.width, let height = image?.size.height {
let disclosureImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
disclosureImageView.image = image
cell.accessoryView = disclosureImageView
}
Images you can use:
What it could look like:
Bellow Code is Swift 3.0 code, and will change the accessoryType color as per tintColor.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "SOME TITLE GOES HERE"
cell.accessoryType = .disclosureIndicator
cell.tintColor = UIColor.blue
let image = UIImage(named:"arrow1")?.withRenderingMode(.alwaysTemplate)
let checkmark = UIImageView(frame:CGRect(x:0, y:0, width:(image?.size.width)!, height:(image?.size.height)!));
checkmark.image = image
cell.accessoryView = checkmark
return cell
}
Swift 5. Extension style ;)
extension UITableViewCell {
func setupDisclosureIndicator() {
accessoryType = .disclosureIndicator
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 7, height: 12))
imgView.contentMode = .scaleAspectFit
imgView.image = UIImage(named: "your_icon_name")
accessoryView = imgView
}
}
Swift 5 & iOS 15 & Xcode 13
Here is an extension which uses SF Symbols, so you have a chevron like the default disclosure indicator one:
extension UITableViewCell {
func addCustomDisclosureIndicator(with color: UIColor) {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 10, height: 15))
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 15, weight: .regular, scale: .large)
let symbolImage = UIImage(systemName: "chevron.right",
withConfiguration: symbolConfig)
button.setImage(symbolImage?.withTintColor(color, renderingMode: .alwaysOriginal), for: .normal)
button.tintColor = color
self.accessoryView = button
}
}
You can use it like this:
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.addCustomDisclosureIndicator(with: .white) // Here your own color
return cell
}
Swift 5 & iOS 11-15
A combination of some answers
extension UITableViewCell {
func addCustomDisclosureIndicator(with color: UIColor) {
accessoryType = .disclosureIndicator
let disclosureImage = UIImage(named: "arrow_right")?.withRenderingMode(.alwaysTemplate)
let imageWidth = (disclosureImage?.size.width) ?? 7
let imageHeight = (disclosureImage?.size.height) ?? 12
let accessoryImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight))
accessoryImageView.contentMode = .scaleAspectFit
accessoryImageView.image = disclosureImage
accessoryImageView.tintColor = color
accessoryView = accessoryImageView
}
}

UITableCell Swipe/Slide Two or Multiple Cell

I want to ask how could I have done this feature you can see in this image:
I know the editActionsForRowAt but I think it's not the solution for the things I need to do, so I added UISwipeGestureRecognizer and my code look like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! ConnectionTableCell
let users = self.users[indexPath.section]
let user = users.userInfo[indexPath.row]
cell.userImage.image = UIImage(named: user.imageUrl)
cell.name.text = user.name
cell.work.text = user.work
cell.selectionStyle = .none
cell.addGestureRecognizer(UISwipeGestureRecognizer(target: self, action: #selector(didSwipeForRow)))
return cell
}
func didSwipeForRow(recognizer: UIGestureRecognizer) {
if recognizer.state == UIGestureRecognizerState.ended {
let swipeLocation = recognizer.location(in: self.tableView)
if let swipedIndexPath = tableView.indexPathForRow(at: swipeLocation) {
let textConstant = tableView.frame.width + 10
let imageConstant = tableView.frame.width - 20
let swipeView = UIView()
swipeView.backgroundColor = UIColor.themeColor(color: .green)
let cell = tableView.cellForRow(at: swipedIndexPath) as! ConnectionTableCell
let height = cell.frame.height
let users = self.users[swipedIndexPath.section]
let user = users.userInfo[swipedIndexPath.row]
cell.addSubview(swipeView)
swipeView.frame = CGRect(x: 0, y: 0, width: imageConstant - 60, height: height)
cell.name.leftAnchor.constraint(equalTo: self.tableView.rightAnchor, constant: textConstant).isActive = true
cell.work.leftAnchor.constraint(equalTo: self.tableView.rightAnchor, constant: textConstant).isActive = true
cell.userImage.rightAnchor.constraint(equalTo: self.tableView.rightAnchor, constant: imageConstant).isActive = true
}
}
}
But the problem is when I swipe a cell its also affecting the reused cell as you can see in this image :
Any suggestions on how to solve this issue? Thanks in advance guys.

Resources