I created a UIViewController that contains two View (Top , Bottom),
the Bottom view expands all the way to the top when clicking on the searchBar. (bottomView height expands, topView height is getting smaller).
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
self.expandBottomView()
return true
}
func expandBottomView() {
let heightToAdd = TopView.frame.height - numOfRequestsTitle.frame.height
RecomandFriendHeight.constant += heightToAdd
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
topTableView.isUserInteractionEnabled = false
}
Both View contain TableViews (topTableView , BottomTableView) all delegates are set I checked.
BottomView Contains another button to collapse the bottomView when needed.
topTableViewCell contains two Buttons and two labels.
bottomTableViewCell contains a label and an imageView.
The Problem is none of the tableViews cells invokes didSelectRowAt.
If you add button to a cell didSelectAt not called on tapping the button. In this case you have to add a selector to this button inside cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customcell
cell.btn.addTarget(self, action: #selector(clickedCell), for: .touchUpInside)
return cell
}
and implement this selector method
func clickedCell(_ sender : UIButton) {
print("clicked")
}
Make
topTableView.isUserInteractionEnabled = true
Related
I have a uicollectionview with a series of custom class cells that have a few textviews and a uibutton. With over 100 cells, I just want to toggle the uibutton image for each respective cell. The uibutton is a favorites button, and like most apps I just want to favorite and "un-favorite" different cells.
NOTE: I tried to add the gesture recognizer in the class directly, but for some reason the image changes, but it highlights multiple cells instead of the specific cell that was clicked
my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SimpleExampleSubCell
cell.backgroundColor = UIColor.init(white: 0.10, alpha: 0.25)
cell.infoLine2TextVw.text = ""
cell.infoLine3TextVw.text = ""
if let heading_name = self.dict_dict_holder[indexPath.item]["Name"]{
cell.headerTextVw.text = heading_name
cell.infoLine1TextVw.text = self.dict_dict_holder[indexPath.item]["Phone"]
}
cell.bringSubview(toFront: cell.headerTextVw)
cell.favorite_button.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(AddFavorite(withSender:))))
return cell
}
#objc func AddFavorite(withSender sender:UIButton){
print("clicked")
//The line below fails each time I run it.
sender.setImage(newImage.png,.normal)
}
Replace
#objc func addFavorite(withSender sender:UIButton){
with
// not recommended use touchUpInside
#objc func addFavorite(_ sender:UITapGestureRecognizer){
let btn = sender.view! as! UIButton
}
OR better
cell.favorite_button.addTarget(self, action:#selector(addFavorite), for: .touchUpInside)
Don't Add tapgestures to buttons , as they they have their own targets like touchUpInside or touchUpOutside and many more
table cells are reused you need to nil them inside cellForRowAt or give an else
if someCondition {
cell.favorite_button.setImage(newImage1.png,.normal)
else {
cell.favorite_button.setImage(newImage2.png,.normal)
}
you have to set the default image (plus everything you want to reset) for each cell in the prepareForReuse() method so it clears up the reused content
I have a tableview, and in each cell I have one button called drop down. So when user presses any option in my drop down - the hidden elements like one more drop down, one name label, one save button will be visible. So again when user presses my save button again those elements will be hidden. Now the issues is when I select my button in two or three cells and if I scroll up and down automatically which and all cell showing the elements that and all getting hide. I need to show which and all cell is clicked and showed the elements.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartDetailsCell", for: indexPath) as! CartDetailsCell
cell.selectionStyle = UITableViewCellSelectionStyle.none
let notClicked = !selectedIndexPaths.contains(indexPath)
print(notClicked)
cell.noOfQtyOuterView.isHidden = notClicked
cell.saveDataButnOtlet.isHidden = notClicked
cell.noOfQtyButnOutlet.isHidden = notClicked
}
#IBAction func dropDownButnClick(_ sender: Any) {
guard let button = sender as? UIButton else {
return
}
let indexPath = IndexPath(item: button.tag, section: 0)
let cell = self.tableView.cellForRow(at: indexPath) as! CartDetailsCell
dropDown.anchorView = button
dropDown.dataSource = ["Edit", "Cancel"]
dropDown.selectionAction = { [unowned self] (index: Int, item: String) in
switch index {
case 0:
cell.noOfQtyOuterView.isHidden = false
cell.saveDataButnOtlet.isHidden = false
cell.noOfComboOuterViewButn.isHidden = false
case 2:
}
}
Once the button is hidden it will never be un-hidden until you explicitly make it unhidden.
"Now the issues is when i select my button in two or three cells and if i scroll up and down automatically which and all cell showing the elements that and al getting hide"
let cell = tableView.dequeueReusableCell(withIdentifier: "CartDetailsCell", for: indexPath) as! CartDetailsCell
As you are using the cell with the hidden button is reused, it will make the button remain hidden for remaining cells
I suggest to use following pattern, will save you time and you'll have a more reusable and pretty code:
protocol CartDetailsCellDelegate: class {
func didTouchDropDownButton(in cell: CartDetailsCell)
....
}
final class CartDetailsCell: UITableViewCell {
....
weak var delegate: CartDetailsCellDelegate?
#IBAction func didTouchDropDownButton(_ sender: UIButton) {
delegate?.didTouchDropDownButton(in: self)
}
...
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.delegate = self
...
}
extension ViewController: CartDetailsCellDelegate {
func didTouchDropDownButton(in cell: CartDetailsCell) {
// Do your stuff here, you have the cell, don't have to play with tags
}
}
I have two images inside one cell of uitableview, these images shows to images from an external server and each tag of them has an id of item which this image represent, I need if I clicked on this image move user to new view controller which show details of this item, I force a problem, where user need to double click to show details instead of one click, the following my code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = self.tableView.cellForRow(at: indexPath as IndexPath) as! prodctCell
Id1stMove = cell.image1st.tag
let tapGesture = UITapGestureRecognizer (target: self, action: #selector(ItemsController.imgTap))
cell.image1st.addGestureRecognizer(tapGesture)
cell.image1st.isUserInteractionEnabled = true
let cell1 = self.tableView.cellForRow(at: indexPath as IndexPath) as! prodctCell
Id2ndMove = cell1.image2nd.tag
let tapGesture1 = UITapGestureRecognizer (target: self, action: #selector(ItemsController.imgTap1))
cell1.image2nd.addGestureRecognizer(tapGesture1)
}
func imgTap()
{
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "testViewController") as? testViewController
let navController = UINavigationController(rootViewController: secondViewController!)
navController.setViewControllers([secondViewController!], animated:true)
self.revealViewController().setFront(navController, animated: true)
revealViewController().pushFrontViewController(navController, animated: true)
secondViewController?.movmentId = Id1stMove
updateCount(itemId: Id1stMove)
}
Yesterday itself I created sample and tried.I got the solution.But I could not post my answer immediately as I had some work.
Now I will give you my answer.I don't expect reputation for my below answer.
When you click or tap the image first time,it navigates.
You don't need to add TapGestureRecognizer for imageView in didSelectRowAt method.You need to add TapGestureRecognizer for image View in cellForRowAt method.
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
let mobiles: [String] = ["iPhone", "Android"]
let images: [String] = ["iPhone.png", "android.png"]
#IBOutlet var tableViewImageTapping: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// number of rows in table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.mobiles.count
}
// create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: "cell")
if (cell == nil) {
cell = UITableViewCell(style:UITableViewCellStyle.default, reuseIdentifier:"cell")
}
cell?.textLabel?.text = self.mobiles[indexPath.row]
let strImageName = images[indexPath.row]
cell?.imageView?.image = UIImage(named: strImageName)
cell?.imageView?.tag = indexPath.row
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
tapGestureRecognizer.numberOfTapsRequired = 1
cell?.imageView?.isUserInteractionEnabled = true
cell?.imageView?.addGestureRecognizer(tapGestureRecognizer)
return cell!
}
// method to run when table view cell is selected
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped table view cell index is \(indexPath.row).")
}
// method to run when imageview is tapped
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let imgView = tapGestureRecognizer.view as! UIImageView
print("your taped image view tag is : \(imgView.tag)")
if (imgView.tag == 0) //Give your image View tag
{
//navigate to next view
}
else{
}
}
}
Output Screenshot
Printed results are
When you click the first image in first click
Then when you click the second image in first click
You need to execute this code in cellForRowAt indexPath instead did select.
As you said you want to use image id from the tag value I suggest below change in addition of adding code in cellForRowAt indexPath:
Change tapGesture code as below:
let tapGesture = UITapGestureRecognizer (target: self, action: #selector(imgTap(tapGesture:)))
And imgTap function:
func imgTap(tapGesture: UITapGestureRecognizer) {
let imgView = tapGesture.view as! UIImageView
let idToMove = imgView.tag
//Do further execution where you need idToMove
}
You are assigning the gesture recognizers in the "did select row at index path" method, this means that the user must select (tap) a cell for the gesture recognizers to be assigned to the images, and then the user must tap the image for those recognizers to react by calling "imgTap()", those are the two taps.
What you should do instead is assign the gesture recognizers in the "cell for row at index path" method, so when you create each cell you also create the gesture recognizers, that way when the user taps an image for the first time the tap is recognized and "imgTap()" is called.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! CustomCell
// Configure the cell...
let tapGesture1 = UITapGestureRecognizer (target: self, action: #selector(ItemsController.imgTap))
cell.image1st.addGestureRecognizer(tapGesture1)
let tapGesture2 = UITapGestureRecognizer (target: self, action: #selector(ItemsController.imgTap))
cell.image2nd.addGestureRecognizer(tapGesture2)
return cell
}
I also recommend changing the code a little so you can call "imgTap()" with a parameter (the id of what was tapped), instead of having 2 methods "imgTap()" and "imgTap1()".
Please don't use force unwrap as! prodctCell
Please use name swift naming conventions
Don't use .tag cell is usually reused it might break in some edge cases
Now back to your question, you already have a custom cell that holds the image.
you have several possibilities
Add the gesture recogniser to the imageView
you can change that to a button
Add a button over the image view (no title or image for it)
Then create an #IBAction for the button/gesture recogniser, and a delegate method that will call the main viewController where you can pass all the data you need from the cell to instantiate the second VC
Update
I would advice against adding the logic of handling the tap in the cellForRow the viewController is not meant to handle and manage his child logic.
I have a switch button in a custom cell that is inserted into the tableView. How can I update the tableview on toggle of the switch button ?
Below is the function where I am inserting the custom tableViewCell that contains the toggleSwitch
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("AvailabilityTableViewCell", owner: self, options: nil)?.first as! AvailabilityTableViewCell
// Configure the cell...
cell.availabilityLabel.text = "Available"
switchIsOn = cell.availabilitySwitch.isOn
return cell
}
UISwitch is a subclass of UIControl which allows you to set a target/action on it:
Implement the following function in your UIViewController:
func toggled(sender: UISwitch) {
// React to switch being toggled here
}
In your cellForRowAt: you can now the add the target/action to the cell's UISwitch:
cell.availabilitySwitch.addTarget(self, action: #selector(toggled:), for: .valueChanged)
I have a label I want to tap on using addGestureRecognizer. I put it in cellForRowAtIndexPath but when I do print(label.text), it prints a label from another cell. But when I put it in didSelectRowAtIndexPath, it prints out the right label for that cell.
What is the best way to fix this?
Here is the code:
var variableToPass: String!
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : MainCell! = tableView.dequeueReusableCellWithIdentifier("MainCell") as! MainCell
variableToPass = label1.text
cell.label1.userInteractionEnabled = true
let tapLabel = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapLabel(_:)))
cell.label1.addGestureRecognizer(tapLabel)
return cell as MainCell
}
func tapCommentPost(sender:UITapGestureRecognizer) {
print(variableToPass)
}
I think you forget to set the tap.tag = indexPath.row for identify which cell you tabbed for Find, for example
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell : MainCell! = tableView.dequeueReusableCellWithIdentifier("MainCell") as! MainCell
variableToPass = label1.text
cell.label1.userInteractionEnabled = true
let tapLabel = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapLabel(_:)))
cell.label1.tag = indexPath.row
tapLabel.numberOfTapsRequired = 1
cell.label1.addGestureRecognizer(tapLabel)
return cell as MainCell
}
func tapLabel(sender:UITapGestureRecognizer) {
let searchlbl:UILabel = (sender.view as! UILabel)
variableToPass = searchlbl.text!
print(variableToPass)
}
There are several issues with your current code: (1) You're setting variableToPass in cellForRowAtIndexPath:, so assuming label1.text is the label belonging to the cell, as the table loads, the variableToPass will always contain the label text of the last loaded cell. (2) cellForRowAtIndexPath: can be called multiple times for each cell (for example, as you scroll) so you could be adding multiple gesture recognizers to a single cell.
In order to resolve issue #1, remove the variableToPass variable entirely and instead directly access the gesture's label view. In order to resolve issue #2, I'd recommend adding the gesture recognizer to your custom MainCell table view cell, but if you don't want to do that, at least only add a gesture recognizer if one isn't already there.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MainCell") as! MainCell
if cell.label1.gestureRecognizers?.count == 0 {
cell.label1.userInteractionEnabled = true
let tapLabel = UITapGestureRecognizer(target: self, action: #selector(ViewController.tapCommentPost(_:))) // I assume "tapLabel" was a typo in your original post
cell.label1.addGestureRecognizer(tapLabel)
}
return cell
}
func tapCommentPost(sender:UITapGestureRecognizer) {
print((sender.view as! UILabel).text) // <-- Most important change!
}