UITableViewCell with button inside in Swift [duplicate] - swift

This question already has answers here:
How to add a button with click event on UITableViewCell in Swift?
(4 answers)
Closed 1 year ago.
I have a UITableView with cells, every cell have information of products, the name of the product and the Id of the product. Every cell has a button that drives you to another screen with more details of the product.
My problem is that when I selects a cell, I have obtain the name and id of the product that belongs to the selected cell thanks to didSelectRowAtIndexPath, but when I touch the button inside the cell I don't trigger didSelectRowAtIndexPath and I can't obtain the id of the product, because of this I can't go to the next screen and show the information related to the selected product.
What could I do?

The question I will ask you which will help solve this is:
Are you using IBAction to transition as the action trigger for the button?
If Yes, then the IBAction will sit under the UITableViewCell which should contain IBOutlet for the UILabels holding the value of name, id and product information.
For example:
class SampleCell: UITableViewCell {
#IBOutlet var nameLabel: UILabel!
#IBOutlet var idLabel: UILabel!
#IBOutlet var informationLabel: UILabel!
#IBAction func action(button: UIButton) {
// you can obtain your information once the button is triggered before navigating
let id = self.idLabel.text
let name = self.nameLabel.text
let information = self.informationLabel.text
// navigate to new screen using delegate protocols
}
}
if you are not using IBOutlets and IBActions as follows, then I will suggest you use them, and create a custom TableViewCell for the product cell. It is the easiest way to access your cell information

Related

How could I keep keyboard up when tableview cells are tapped?

I am a beginner learning Swift and trying to build a search page with Swift. In my search page of the app, I have added two Views in my storyboard with one View above the other.
The upper View contains a Collection View where I have two prototypes of collection view cells. The first type of the cells has Label. The second type of the cells has TextField.
The other View on the bottom half of the screen contains a dynamic Table View where I have a list of items that can be selected. Each row of the table view cells has a selection item.
So, when I tap on a table view cell, the selection item will appear in the collection view. If I type a keyword in the TextField in the collection view, table view reloads and shows all the selection items that has the keyword, so I can tap and add an item to the collection view.
I would like to keep adding by typing a keyword after I tap on a searched item in the table view. So, I made the first cell showing selected items with labels and the second cell that has the TextField separated into two sections of the collection view. So, I only reload the first section (without TextField) for each selection. But somehow the keyboard automatically resign whenever I tap on the table view cell to add an item to the collection view.
Is there any way I can keep the keyboard up even when I tap on the tableview cells?
The keyboard also resigns when I tap the collection view cells.
I would appreciate your advice. Thanks.
I hope you are having a good day.
You can try calling this method on the UITextField you would like to show the keyboard for (maybe call it after the user taps on the UITableViewCell):
textField.becomeFirstResponder()
where "textField" is the variable name of your UITextField.
Please let me know if this fixed your issue.
Edit #1
Hello! Since my previous solution did not achieve your intended behavior. There is another solution in my mind, however I have not tried it before.
As an introduction to the concept of delegation, there is a method created by Apple called "textFieldShouldEndEditing" which is called by Apple whenever any keyboard will disappear on any text field.
This method is created by Apple, but you can override it (i.e. customize it) to suit your needs and tailor its behavior.
To override this method you have to assign your class as the delegate of UITextField by adding UITextFieldDelegate to your class definition as follows:
class YourClassName: UIViewController, UITextFieldDelegate { }
Now you have to set your class as the delegate by saying textField.delegate = self For every UITextField you create in your collection views
You then can re-create the method we discussed earlier in your class:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
//let's implement it the next steps, but for now, let's return true.
return true
}
Now instead of Apple calling their version of the method, they will call yours.
You then can create a variable in the top level of your class (I will let you know where this will be helpful later), and "maybe" name it as:
var isCellBeingClicked = false
Now upon clicking on a cell, make this variable true, I believe you are using the method didSelectRowAt (but you could be using any other method which is fine):
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
[...]
isCellBeingClicked = true
[...]
}
Now back to our customized method textFieldShouldEndEditing mentioned in step 3. You can add this implementation:
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
//If a cell is being clicked right now, please do not dismiss the keyboard.
if isCellBeingClicked {
isCellBeingClicked = false //reset the value otherwise the keyboard will always be there
return false
}
else { return true }
}
Please let me know if this fixes your issue.
Best regards

Setting the text of a UILabel with a constant

I am a total newby to xCode and Swift so please excuse me if this question is silly.
I am trying to update 2 UILabels and a UIImageView by using the sender.currentTitle of the button pressed.
If a user presses the 'Honduras' button then I want to populate the 2 UILabel with it's corresponding information and the UIImageView with its corresponding image file.
I have the first UILabel working and the UIImageView working but cannot find a way to populate the 2nd UILabel with its corresponding text (which is stored in a constant).
UILabel 1 is called #IBOutlet weak var countryLabel: UILabel!
UILabel 2 is called #IBOutlet weak var peopleLabel: UILabel!
UImageView is called #IBOutlet weak var peopleUIImageView: UIImageView!
The information/file name I want to pass into these 3 are called:
"Honduras"
let peopleHondurasText = "The Lenca"
"peopleHonduras.png"
I have the UILabel 1 working like this:
countryLabel.text = sender.currentTitle
I have the image working by calling this func:
func findCountryImages() {
peopleUIImageView.image = UIImage(named: "people\(countryLabel.text! .filter { !" ".contains($0) }).png")
}
and I am trying to call the constant "peopleHondurasText" like I did the UIImage but it isn't working.
Here is my very amateur code:
peopleLabel.text = "people\(countryLabel.text! .filter { !" ".contains($0) })Text"
Where this:
"people\(countryLabel.text! .filter { !" ".contains($0) })Text"
Should be equal to the constant named:
peopleHondurasText
I want to be able to do this so if a user clicks on any country button it will populate those 2 UILabels and UIImageViews with that countries text and images.
I know I must be doing something fundamentally incorrect or maybe going about this complete in the wrong but if anyone could let me know either how to pass the constant name into the UILable
or tell me that you cannot do this and I should try something different, that would be greatly appreciated.
How come you don't just do:
peopleLabel.text = peopleHondurasText

Detect backspace in empty UITextField Swift Working Sample

I know that this question may sounds duplicate, but looking at the several answer, nothing is working for me yet.
Basically I have a Quizz App, a question is shown and the user needs to fill several UITextFields to answer the question (i.e. if the answer is VENICE, 6 UITextFields will be shown, 1 per letter).
It was able to detect one character in the UITextFields and once the user hits a key it will jump to the following UITextField. I use the tag of the UITextField and the method becomeFirstResponder.
The problem is that I will like to detect the backspace when a UITextField is empty so I will jump to the previous UITextField.
I have tried this solution from Jacob Caraballo (Detect backspace in empty UITextField) but I am not sure, how to use it with my existing UITextField.
For example, I have tried:
// #IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField1:MyTextField!
But calling the delegate
textField1.myDelegate = self
It crashes
I also notice, that using the Jacob's solution I won't be able to check which UITextField was used as the func textFieldDidDelete() doesn't not have an UITextField as parameter and I will need to check its tag i.e.
If textField.tag == 5 {
textField4.becomeFirstResponder()
}
Any help on this please?
If you use Jacob's solution, the deleteBackward method will be called with the current UITextField instance. So you can add a protocol to that UITextField class and pass it back to your view.
Something like this:
protocol MyTextFieldDelegate: class {
func backwardDetected(textField: MyTextField)
}
class MyTextField: UITextField {
weak var myTextFieldDelegate: MyTextFieldDelegate?
override func deleteBackward() {
super.deleteBackward()
self.myTextFieldDelegate?.backwardDetected(textField: self)
}
}

UITableViewCell with undetermined number of items

I need to make a cell with some buttons. This buttons are answers options to a question. But the question and the number of buttons (answers) are not determined because I get these data from Alamofire. So there may be 2, 3, 6, or any number of buttons.
Is there a way to add these buttons programmatically depending on (for example) the number of items in an array, in a way that they look well constrained? Like a stack view?
Thanks in advance
A stack view is certainly a way of constraining any number of views into a column (or row). So that sounds like the best way to go.
This is a sneaky way to do it, but if you know the maximum number of buttons you're going to have, you can add it directly to your custom prototype cell on your storyboard without adding buttons programatically.
Solution (Written in Swift 4, but a general answer)
Assuming there is a maximum of 8 answers in any question, create 8 buttons in your custom prototype cell. Add constraints as you like to make them look pretty!
Remember to give your cell a unique identifier ("CustomCell" in my case).
Go to File > New File > Cocoa Touch Class > Select "TableViewCell" Subclass
& give it an appropriate name (in my case CustomCellTableViewCell.swift). This will contain all your UI components outlets.
Select the prototype cell in your storyboard. Navigate to the third icon from the left and select "CustomCellTableViewCell" as your class.
Control+Drag outlets of your buttons and fields that you're going to be working with from the storyboard to your newly created CustomCellTableViewCell.swift. The file should now look something like this:
class CustomCellTableViewCell: UITableViewCell {
#IBOutlet weak var question: UILabel!
#IBOutlet weak var answerOne: UIButton!
#IBOutlet weak var answerTwo: UIButton!
...
...
#IBOutlet weak var answerEight: UIButton!
}
The next few steps will be in the TableviewDataSource function func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell. Remember to cast the TableviewCell as a CustomCell:
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCellTableViewCell
Put all the answer buttons in an array
var answerButtons = [cell.answerButtonOne, cell.answerButtonTwo..., cell.answerButtonEight]
Now you can set the answer button text in a loop as follows:
for i in 0..<answerButtons.count {
if i < data[indexPath.row].answers.count { // if the answer exists, add it to the button
cell.answerButton[i].isHidden = false // show button if answer exists
cell.answerButton[i].setTitle(data[indexPath.row], for: .normal)
} else {
cell.answerButton[i].isHidden = true // hide that button
}
}

How to programmatically set an NSPopUp title. Swift4 OSX

I have an IB NSPopUpButton with a list of items and a number of NSTextFields.
The items from the popup are used to populate the text fields (ingredients) until a recipe is complete.
I would like to reset the popup title after each item is used but cannot find the code and syntax to do this.
I'd also like to be able to click on any of the text fields after selecting an ingredient to drop it there. Drag and drop from the popup would be ideal but I cannot find a simple way to do either so am currently using another button adjacent to each text field to initiate the drop.
This is neither elegant nor ideal.
Hopefully someone can propose better solutions.
My code currently looks like this
var ItemLabel: String = ""
#IBAction func Ingredients(_ sender: NSPopUpButton){
ItemLabel = sender.titleOfSelectedItem ?? "Nil"
}
#IBOutlet weak var Ingredient1: NSTextField!
#IBAction func AddIngredient1(_ sender: NSButton){ // button next to text field
Ingredient1Label.stringValue = ItemLabel
// Here I need to reset the popup title
}