How to delete a Cell from Collection View? - ios

I want to delete cell from UICollectionview,when user touchUpInside(Button) to remove cell.
Here is my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! CollectionViewCell
cell.myLabel.text = self.items[indexPath.row]
cell.deleteBtn?.layer.setValue(indexPath.row, forKey: "Cdelete")
cell.deleteBtn?.addTarget(self, action: Selector(("deleteColor:")), for: UIControlEvents.touchUpInside)
cell.backgroundColor = UIColor.cyan // make cell more visible in our example project
return cell
}
func deleteColor(sender:UIButton) {
let i : Int = (sender.layer.value(forKey: "Cdelete")) as! Int
self.items.remove(at: i)
collectionView.reloadData()
}
Where i am doing wrong?

set tag for your deletebutton for fetch the current cell/ know the which cell you tapped
cell.deleteBtn?.tag = indexPath.row
cell.deleteBtn?.addTarget(self, action: #selector(yourVCName. deleteColor(_:)), for: .touchUpInside)
and call like
#IBAction func deleteColor(_ sender: UIButton){
print("Button pressed 👍 ")
// continue your work
var hitPoint = sender.convert(CGPoint.zero, to: yourCollectionViewName)
var hitIndex: IndexPath? = yourCollectionViewName.indexPathForRow(at: hitPoint)
self.items.remove(at: hitIndex.row)
self.yourCollectionViewName.performBatchUpdates({
self.yourCollectionViewName.deleteItems(at: [hitIndex])
}) { (finished) in
self.yourCollectionViewName.reloadItems(at: self.yourCollectionViewName.indexPathsForVisibleItems)
}
}

Related

Check box check and unchecked not persisting in my table view

My task I am trying to show tableView with check box button inside the popup viewcontroller.
Whenever user click the button it is changing check and uncheck but I need to do when I click done button I have to keep user checked and if click cancel it should uncheck(which is user checked before click cancel). I need to understand and fix this task.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
cell.myCellLabel.text = self.animals[indexPath.row]
if selectedRows.contains(indexPath)
{
cell.checkBox.setImage(UIImage(named:"check.png"), for: .normal)
}else{
cell.checkBox.setImage(UIImage(named:"uncheck.png"), for: .normal)
}
cell.checkBox.tag = indexPath.row
cell.checkBox.addTarget(self, action: #selector(checkBoxSelection(_:)), for: .touchUpInside)
return cell
}
// method to run when table view cell is tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? MyCustomCell else {
return
}
if self.selectedRows.contains(indexPath) {
self.selectedRows.remove(at: self.selectedRows.index(of: indexPath)!)
cell.checkBox.setImage(UIImage(named:"uncheck.png"), for: .normal)
} else {
self.selectedRows.append(indexPath)
cell.checkBox.setImage(UIImage(named:"check.png"), for: .normal)
let indexPath = tableView.indexPathForSelectedRow //optional, to get from any UIButton for example
let currentCell = tableView.cellForRow(at: indexPath!) as! MyCustomCell
}
}
#IBAction func cancelPopup(_ sender: Any) {
self.removeAnimate()
}
#IBAction func donePopUp(_ sender: AnyObject) {
self.removeAnimate()
}
You may consider using basic taleview cell with setting acessoryType . Putting checkbox and labels all at the left seems giving poor UX
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DefectCell", for: indexPath)
let category = defectSet [indexPath.section]
let item = category.items[indexPath.row]
cell.textLabel?.text = item.name
cell.selectionStyle = .none
let isFound = User.shared.selectedDefect.filter{ $0.id == item.id }.count > 0
if (isFound)
{
cell.accessoryType = .checkmark
}
else
{
cell.accessoryType = .none
}
return cell
}

Swift - want to make changes when a button clicked which is inside a collection view cell

I have created a collection view cell which include a UIView and inside the UIView, there is a button.
What I'm trying to do is when the button clicked it will change the UIView border color.
And I load data from server and display it to the collection view.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CypherCollectionViewCell", for: indexPath as IndexPath) as! CypherCollectionViewCell
cell.tickButton.addTarget(self, action: #selector(tickButtonClicked(sender:)), for: .touchUpInside)
return cell
}
#objc func tickButtonClicked( sender: UIButton) {
if sender.isSelected {
sender.isSelected = false
// To change the UIView border color
} else {
sender.isSelected = true
// To change the UIView border color
}
}
Thank you !
You can convert the button points into viewpoints and get the desired cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CypherCollectionViewCell", for: indexPath as IndexPath) as! CypherCollectionViewCell
cell.tickButton.addTarget(self, action: #selector(tickButtonClicked(sender:)), for: .touchUpInside)
return cell
}
#objc func tickButtonClicked( sender: UIButton) {
var convertedPoint : CGPoint = sender.convert(CGPoint.zero, to: self. collectionView)
var indexPath = self. collectionView.indexPathForItemAtPoint(convertedPoint)
let cell = self. collectionView.cellForItemAtIndexPath(indexPath) as! CypherCollectionViewCell
if sender.isSelected {
sender.isSelected = false
// To change the UIView border color
cell.view.borderColor = UIColor.blue()
} else {
sender.isSelected = true
// To change the UIView border color
cell.view.borderColor = UIColor.red()
}
}

Check if text field in collectionView is empty

I have a collection view (CollectionViewController) with 3 cells (each cell has it's own class). In the first cell (TextCell) I have a text field and a button (nextButton). When I press the button I want to check if the text field is empty or not. If it's not empty, I want to switch to the second cell.
CollectionViewController:
let textCell = TextCell()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath)
// TextCell
if indexPath.item == 0 {
let tCell = collectionView.dequeueReusableCell(withReuseIdentifier: textCellId, for: indexPath)
let nextButton = textCell.nextButton
nextButton.addTarget(self, action: #selector(handleNextButton), for: .touchUpInside)
return tCell
}
return cell
}
//Handle Action
#objc func handleNextButton() {
let text = textCell.TextField.text
if text?.isEmpty == false {
scrollToIndex(menuIndex: 1)
} else {
print("Text field is empty.")
}
}
The problem is that every time i check if the text field is empty or not, it say's it is empty although it's not.
To identify whether the UITextField inside UICollectionViewCell is empty or not, you need to pass index position when button is clicked. To pass index position you can use tag. By using tag you can get clicked index position. After getting position, you can access elements from current index position by using cellForItemAtIndexPath . You can find the particular index position UITextField is empty or not using the fetched cell reference
In Your cellForItemAt
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_CELL_IDENTIFIER", for: indexPath) as! YOUR_UICOLLECTIONVIEW_CELL
cell.nextBtn.tag = indexPath.item
cell.nextBtn.addTarget(self, action: #selector(handleNextButton(_:)), for: .touchUpInside)
return cell
} else {
///use your other cells here
}
}
In your ViewController
func handleNextButton(_ sender:UIButton){
let indexPath = IndexPath(item:sender.tag,section:0)
let cell = YOUR_COLLECTIONVIEW.cellForItem(at: indexPath) as! YOUR_UICOLLECTIONVIEW_CELL
if cell.txtFld.text == "" {
print("TextField is empty")
} else {
print("TextField not empty")
}
}
Hope this will help you
First - Remove the next line, It's not needed and is definitely wrong!
let textCell = TextCell()
Now replace your func with that:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// TextCell
if indexPath.item == 0 {
let tCell = collectionView.dequeueReusableCell(withReuseIdentifier: textCellId, for: indexPath) as! TextCell
let nextButton = tCell.nextButton
nextButton.addTarget(self, action: #selector(handleNextButton), for: .touchUpInside)
return tCell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellId, for: indexPath)
return cell
}
And The Handler
//Handle Action
#objc func handleNextButton(sender: UIButton) {
let tCell = sender.superview as! TextCell
let text = tCell.TextField.text
if text?.isEmpty == false {
scrollToIndex(menuIndex: 1)
} else {
print("Text field is empty.")
}
}

How to present a ViewController after pressing a button inside of a CollectionViewCell

Hey i'm new to programming and my problem is, i have a UICollectionViewController with 4 cells that are horizontal scrollable. Inside of the 4th cell i have a UIButton(optionsButton) on top of a UIView (ProfileContainerView).
The UIViewController I want to present is called ProfileEditViewController and is set up in Main.storyboard.
How can i present a UIViewController after pressing this button?
ProfileCell:
class ProfileCell: UICollectionViewCell {
let profileContainerView: UIView = {
let view = UIView()
return view
}()
lazy var optionsButton: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(#imageLiteral(resourceName: "Settings"), for: UIControlState.normal)
btn.addTarget(self, action: #selector(handleOptionsButton), for: UIControlEvents.touchUpInside)
return btn
}()
#objc func handleOptionsButton() {
print("Button pressed")
}
}
HomeViewController:
class HomeViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let profileCelId = "profileCell"
override func viewDidLoad() {
super.viewDidLoad()
setupSwipeView()
}
func setupSwipeView() {
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cell)
collectionView?.register(ProfileCell.self, forCellWithReuseIdentifier: profileCelId)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 3 {
return collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
}
return cell
}
}
You can use delegates to implement this.
Below is the code to implement this
protocol ProfileCollectionViewCellDelegate {
func buttonPressedAtIndexPath(inCell: ProfileCell)
}
class ProfileCell: UICollectionViewCell {
var delegate : ProfileCollectionViewCellDelegate?
let profileContainerView: UIView = {
let view = UIView()
return view
}()
lazy var optionsButton: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(#imageLiteral(resourceName: "Settings"), for: UIControlState.normal)
btn.addTarget(self, action: #selector(handleOptionsButton), for: UIControlEvents.touchUpInside)
return btn
}()
#objc func handleOptionsButton() {
if self.delegate != nil {
self.delegate?.buttonPressedAtIndexPath(self)
}
}
}
For your HomeViewController
class HomeViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, ProfileCollectionViewCellDelegate {
let profileCelId = "profileCell"
override func viewDidLoad() {
super.viewDidLoad()
setupSwipeView()
}
func setupSwipeView() {
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cell)
collectionView?.register(ProfileCell.self, forCellWithReuseIdentifier: profileCelId)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
cell.delegate = self
return cell
}
fun buttonPressedAtIndexPath(inCell: ProfileCell) {
let indexOfCell = self.collectionView.indexPath(for: cell)
if indexOfCell.row == 3 {
//Do your work here
}
}
}
You can present your ProfileEditViewController, which is styled in your Main.storyboard the following way:
1) Give your ProfileEditViewController a StoryBoard ID. E.g. "ProfileEditViewController" - Some question regarding this is here: What is a StoryBoard ID and how can i use this?
2) Register the UIViewController for the action on the UIButton or offer an appropriate callback functionality.
As your HomeViewController is also your Collection View's datasource, you can easily extend your DataSource method
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell`
Implementation could look like:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 3 {
let profileCell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
if let _cell = cell as? ProfileCell,
let button = _cell.optionsButton as? UIButton {
button.addTarget(self, action: #selector(handleOptionsButton), forControlEvents: UIControlEvents.TouchUpInside)
}
return profileCell;
}
return cell
}
Make sure that your buttons Action is now also being implemented by your HomeViewController
#objc func handleOptionsButton() {
print("Button pressed")
}
3) Now in HomeViewController.handleOptionsButton you need to provide a functionality to support the transition to that specific Controller with the desired StoryboardID:
let storyboard = UIStoryboard(name: "Main", bundle:Bundle.main)
let controller = storyboard.instantiateViewController(withIdentifier: "ProfileEditViewController")
self.present(controller, animated: true, completion: nil)
let proCell = ProfileCell()
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cell, for: indexPath)
if indexPath.item == 3 {
let profileCell = collectionView.dequeueReusableCell(withReuseIdentifier: profileCelId, for: indexPath)
let button = proCell.optionsButton
button.addTarget(self, action: #selector(handleOptionsButton), for: UIControlEvents.touchUpInside)
return profileCell;
}
return cell
}

CollectionView Custom Cell accessing atributes outside of the cell

I am trying to change some attributes of the custom view cell in my collection view outside of the cell, but I can not figure it out what I am doing wrong:
In cellForItem I have :
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PatientProfileCell", for: indexPath) as! PatientQuestionCell
if Auth.auth().currentUser?.uid == userID {
cell.commentButton.setTitle("Edit post", for: .normal)
cell.commentButton.addTarget(self, action: #selector(editPostAction), for: .touchUpInside)
}
} else {
print("Not the current user for collection view")
}
}
Everything works perfectly here but when I do trigger the action nothing happens. This is the function :
//post actions
func editPostAction() {
print("Edit post Enabled")
let cell = PatientQuestionCell()
cell.questionView.isEditable = true
cell.questionView.isSelectable = true
cell.questionView.isScrollEnabled = true
cell.questionView.becomeFirstResponder()
}
How can I change the attributes of the cell with this function?
You can make use of the tag property of UIButton like this:
Inside your collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) method, add this line of code:
cell.commentButton.tag = (indexPath.section * 100) + indexPath.item
Then set the target of your button like this:
cell.commentButton.addTarget(self, action: #selector(editPostAction(sender:)), for: .touchUpInside)
Now, add a new method, which is your selector:
func editPostAction(sender: UIButton) {
let section = sender.tag / 100
let item = sender.tag % 100
let indexPath = IndexPath(item: item, section: section)
let cell = self.collectionView?.cellForItem(at: indexPath) as! PatientQuestionCell
cell.questionView.isEditable = true
cell.questionView.isSelectable = true
cell.questionView.isScrollEnabled = true
cell.questionView.becomeFirstResponder()
}

Resources