I'm working on the "settings" portion of my app. When one of the cells is clicked, I need to transition to a new View Controller depending on which cell was clicked.
I have found a ton of answers, but they all seem to not go far enough. I understand how to set up a segue to a new view controller and I understand how to use didSelectRowAt Indexpath to show which cell was clicked. I can figure out the transition, but I can't figure out many different transitions based on which cell was clicked.
Is there a way to do this with dynamic cells or should I be using static?
If you have fixed amount of cells, I'd go for static cells. However if you want to use dynamic cells, you can create something like enum with cases that store row index.
fileprivate enum Row: Int {
case volume = 0
case notification = 1
}
Then in didSelectRowAt delegate method:
let row = Row(rawValue: indexPath.row)!
switch row {
case .volume:
// Navigate somewhere
case .notification:
// Navigate somewhere
}
Related
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
In my current application, I have a UITableViewController that allows me to segue to three different indices depending on the row selected. If I select row one, I segue to a view controller with three UITextFields. If I select row two, I segue to a NEW view controller with one UITextField. If I select row three, I segue to ANOTHER NEW view controller with five UITextFields. I am looking for a way to condensing the view controllers I am going to into one view controller that will dynamically hide/unhide or remove/add the needed number of UITextFields depending on the index selected in the table view controller. I need the text fields to display in a vertical stack view.
Although it would be very valuable, I am not looking for a solution/example from someone, but rather letting me know some topics I can research would be extremely helpful.
Thank you for your time,
Tony
There might be different approaches for this problem, but I would create a stackView in the NEW view controller with the maximum possible number of textFields embedded. Lets say the VC with most textFields can contain 3 textFields. Create your stackView with 3 textFields inside.
Then segue the indexPath.row of tableView to the NEW VC, it can hold a variable of Integer like:
var index: Int?
In didSelectRowAt method of tableView:
performSegue(withIdentifier: "yourIdentifier", sender: indexPath.row)
In prepareForSegue method:
if segue.identifier == "yourIdentifier"
let vc = segue.destination as! NEWViewController
vc.index = sender
Set tag to your textFields in your NEW View controller, so you can know which textField you will want to delete depending on index.
Then in viewDidLoad of your newViewController, you can remove textFields from your stackView according to the index (Then you might run into which ):
var counter = 0
while counter < index {
answerStackView.subviews.forEach { (view) in
if counter < index {
if view is UITextField {
if view.tag == /*something here to delete specific textFields depending on index. */ {
view.removeFromSuperview()
}
}
}
counter += 1
}
}
have a table view which consists of various different xib files for different question types. One such question is a multi option answer. For this row type, the row itself consists of another tableview each row has a label and switch for the number of options for that question and an overall switch above this inner table to mark this question as na. so When this na switch is tapped, I neeed to deselect all switches existing in the inner row. I have tried the following, but i have an issue if there are so many options that not all cells in the inner table are visible on screen:
#IBAction func switchChange(_ sender: UISwitch) {
let mcAnswerTable = sender.superview?.superview?.superview?.superview as! UITableView
for rows in mcAnswerTable.visibleCells {
if condition {
if let row = rows as? MCAnswerCell {
row.enabled.setOn(false, animated: true)
}
}
}
}
Basically avoid to manipulate the view (cell) directly unless you have no choice.
Here you have one. Create an appropriate model and use the controller to make the changes.
For the table view containing the switches use a custom class (let's call it Foo) with an isSelected property as data source model.
In cellForRow set the isOn property of the switch to the state of isSelected.
Subclass the table view cell and add a property of Foo and an IBAction for the switch.
In cellForRow pass the Foo instance to the custom cell to be able to update the isSelected property in the IBAction. Due to reference semantics the changes persist in the data source.
To deselect the switches call dataSourceArray.forEach {$0.isSelected = false} und tableView.reloadData()
Another huge benefit is that you have access to the state of all switches even of the cells which are not visible currently.
I have a main table view controller with static cells that have a title and then a detail label. When the user clicks on "cell 1" they are taken to a second table view controller with static cells. They choose from a list ( only one cell can be picked) and then when they hit the back button whatever cells title they picked is transferred into the detail label of the cell they clicked on. The main view controller has outlets to each detail label. I've messed with it for two days and can't seem to get it to work
Add a delegate property that is type of DismissDelegate to your second view controller and set it to the first controller.
Add this protocol
protocol DismissDelegate {
func selectedCell(index : int)
}
When the second view is dismissed e.g. in the viewWillDisapper method, call the selectedCell method and pass it the selectedCell
delegate.selectedCell(self.tableView.indexOfSelectedCell) //i don't know the correct function
Then in the main view controller conform to the protocol and do whatever you need to do with the index
func selectedCell(index : int) {
//whatever you need to do with the index
}
There are several ways of solving this problem.
Using Delegate
You just implement a delegate and get the data back from the secondary view controller.
In the secondary view controller, you can call a delegate like this.
self.delegate.dataInputed(xxx)
and the first view controller's dataInputed method will be called.
In the dataInputed Method, you can update the value of the data source for the selected indexPath, and reload the Data
Send Notification
You just keep the selected table cell indexPath, and after receiving a notification from the secondary detail view controller, you can update the value of the data source for the selected indexPath, and reload the table.
in my code i have a tableView and several labels..
I want that the when the user click on cell and after that click on one of the labels, the text in the label will be same as the text in the row that be clicked.
Q1. How can i enable all labels to be clickable and connect to one function that will point on the specific label each time the user click on it?
Q2. I tried to make the same gesture to all labels with UITapGestureRecognizer.. apparently this gesture refers only to the last label (Lbl4 down here in code example).. it means that the text in Lbl1 in my func change only by clicking on Lbl4.. why is that? and how can i change it that it will refers to all labels?
override func viewDidLoad() {
super.viewDidLoad()
let aSelector : Selector = #selector(ViewController.lblTapped)
let tapGesture = UITapGestureRecognizer(target: self, action: aSelector)
tapGesture.numberOfTapsRequired = 1
Lbl1.addGestureRecognizer(tapGesture)
Lbl2.addGestureRecognizer(tapGesture)
Lbl3.addGestureRecognizer(tapGesture)
Lbl4.addGestureRecognizer(tapGesture)
}
func lblTapped(){
Lbl1.text = self.currentPlayerChooseInRow
}
Thanks for advance...
Firstly, you need to understand UITableView object. UITableView is an array of cells, ok? Then, you need use some methods associated to UITableView like numberOfRowsInSection (where app knows the number of cells) and cellForRowAtIndexPath (where app knows cell will be)
About your questions, i recomend you to use outlets to connect labels, buttons, objects to the controller (try to not use gestures if it is not necessary)
Finally, object cells are programmed into cell. If you have a complex cell, you will need a custom cell controller.