TableView Inside tableView Cell In swift - swift

In this image I have two section in this table view . In the second section there is a tableview inside the cell. i want to fetch the textfield data of the “inner table view” in the current class. How to do this? followings are the code for my tableview cell .I want to fetch "InerTableViewCell1" data in "outerTableView". How to do this?
//MARK- UITableViewDataSource
extension outerTableView: UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell1 = tableView.dequeueReusableCell(withIdentifier: "TableViewCell1", for: indexPath) as? TableViewCell1
return cell1!
}
else{
let cell2 = tableView.dequeueReusableCell(withIdentifier: "TableViewCell2", for: indexPath) as? TableViewCell2
cell2!.innerTableView.reloadData()
return cell2!
}
}
class TableViewCell2: UITableViewCell {
//MARK- IBOutlet
#IBOutlet weak var innerTableView: UITableView!
//MARK- Properties
var rowNumber = 1
//MARK- Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
innerTableView.dataSource = self
innerTableView.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
//MARK- UITableViewDataSource
extension TableViewCell2: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("row number is \(rowNumber)")
return rowNumber
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "InerTableViewCell1", for: indexPath) as? InerTableViewCell1
return cell!
}
}
}
class InerTableViewCell1: UITableViewCell {
//MARK- IBOutlet
#IBOutlet weak var firstUserNameTextField: UITextField!
#IBOutlet weak var firstAdressTextField: UITextField!
#IBOutlet weak var secondUserNameTextField: UITextField!
#IBOutlet weak var secondAdressTextField: UITextField!
//MARK- Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

Related

Swift UITableview Reload Cell

I'm stuck with the following, any inputs would be highly appreciated.
My app has a UITableViewController with custom cells. Let's name its UITableView as TABLE VIEW-1. I am using XIB as its custom cell. Inside that xib, there is another UITableView, (TABLE VIEW-2), with another XIB as its custom cell.
My question is, How can I reload cells of (TABLE VIEW-2) from (TABLE VIEW-1) once I get data from an API in (TABLE VIEW-1). I want to use delegate and protocols to do this.
OR, What would be the correct way of performing this and how would I go about it?
Create a reference of TableView1 in the TableView2 ViewController. You can do this by
-- Open the Assistant Editor
-- Right-click and drag from your UI element (i.e. label) to the code file
-- Xcode auto inserts code for you to create the name and connection
Then call tableView2.reloadData(), where tableView2 is the name of the outlet you just created.
Create a reference of the TABLE VIEW-2 in the TABLE VIEW-1 custom cell (TABLE VIEW-1 CELL)
Create a method inside TABLE VIEW-1 CELL to reload its data alone with the TABLE VIEW-2 (Optional but useful to organize your code)
Inside the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell of the TABLE VIEW-1 call reload function
class ViewController: UIViewController {
#IBOutlet weak var mainTable: UITableView!
let sampleData = [
(section: "News", SubSections: [
"Breaking news",
"Current Affairs",
"Local"
]) ]
override func viewDidLoad() {
super.viewDidLoad()
self.mainTable.estimatedRowHeight = 200
self.mainTable.rowHeight = UITableView.automaticDimension
let nib: UINib = UINib(nibName: String(describing: MainCell.self), bundle: Bundle.main)
self.mainTable.register(nib, forCellReuseIdentifier: String(describing: MainCell.self))
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.sampleData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: MainCell = tableView.dequeueReusableCell(withIdentifier: String(describing: MainCell.self), for: indexPath) as! MainCell
let sectionData = self.sampleData[indexPath.row]
cell.setUpData(title: sectionData.section, data: sectionData.SubSections)
return cell
}
}
class MainCell: UITableViewCell {
#IBOutlet weak var sectionTitle: UILabel!
#IBOutlet weak var internalTable: UITableView!
var tableData:[String]?
override func awakeFromNib() {
super.awakeFromNib()
self.internalTable.estimatedRowHeight = 200
self.internalTable.rowHeight = UITableView.automaticDimension
let nib: UINib = UINib(nibName: String(describing: InsideCell.self), bundle: Bundle.main)
self.internalTable.register(nib, forCellReuseIdentifier: String(describing: InsideCell.self))
}
func setUpData(title: String, data:[String]) {
self.sectionTitle.text = title
self.tableData = data
self.internalTable.reloadData()
}
}
extension MainCell: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
self.tableData?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: InsideCell = tableView.dequeueReusableCell(withIdentifier: String(describing: InsideCell.self), for: indexPath) as! InsideCell
if let subSectionData = self.tableData?[indexPath.row] {
cell.subSectionTitle.text = subSectionData
}
return cell
}
}
class InsideCell: UITableViewCell {
#IBOutlet weak var subSectionTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

Get and pass text from a TextField which is in a custom TableViewCell subclass

How can I use the text in a textField from a custom Cell?
This is the Receiving Controller:
class ShowName: UIViewController {
#IBOutlet weak var showName: UILabel!
#IBAction func unwindToShowNameData(_ unwindSegue: UIStoryboardSegue) {
let sourceViewController = unwindSegue.source as! enterName
showName.text = sourceViewController.name
}
#IBAction func unwindToShowName(_ unwindSegue: UIStoryboardSegue) {
}
}
This is the Sending Controller:
class enterName: UIViewController, UITableViewDataSource, UITableViewDelegate {
var name: String?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! nameCell
return cell
}
#IBAction func clickSave(_ sender: UIBarButtonItem) {
let cell = nameCell()
name = cell.nameText.text
performSegue(withIdentifier: "passData", sender: self)
}
}
This is the class Cell with TextField:
class NameCell: UITableViewCell {
#IBOutlet weak var nameText: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Any ideas?
Actually that's the same solution as my suggestion in your previous question.
Add a callback in the cell and call it when the text field delegate method is called. Don't forget to connect the text field delegate in Interface Builder.
And please name classes and structs always with starting uppercase letter
class NameCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var nameText: UITextField!
var callback : ((UITableViewCell, String) -> Void)?
func textFieldDidEndEditing(_ textField: UITextField) {
callback?(self, nameText.text)
}
}
If you have more than one row you need to declare a data source array to maintain the values of the text fields. This is an example for 4 rows
var values = ["", "", "", ""]
These are the data source methods, in cellForRow the callback updates the model
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! NameCell
cell.nameText.text = values[indexPath.row]
cell.callback = { [unowned self] cCell, cName in
let currentIndexPath = tableView.indexPath(for: cCell)!
self.values[currentIndexPath.row] = cName
}
return cell
}
The benefit is you are independent of the cells in the clickSave method. Get the values from the data source array. And you can pass the name as sender parameter and hand it over in prepare(for segue
#IBAction func clickSave(_ sender: UIBarButtonItem) {
let name = values[0]
performSegue(withIdentifier: "passData", sender: name)
}

UISwitches in UITableViewCell change states together

I have a very strange problem in my Swift project. I use UIswitch in my dynamic cells in my one-section uitable. Whenever I click on the 6th switch, the first one changes its state with it and vice versa. The .valueChanged function only works for the one that is clicked (correct behaviour).
I cannot figure out why the switches change state together.
This is the code for table cells:
import UIKit
class RoutineTableViewCell: UITableViewCell {
#IBOutlet weak var selectionSwitch: UISwitch!
#IBOutlet weak var title: UILabel!
#IBOutlet weak var previewImage: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
and here is the code in my table view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RoutineTableReuseIdentifier, for: indexPath) as? RoutineTableViewCell
else{
return RoutineTableViewCell()
}
let exercise = section!.exercises[indexPath.row]
cell.title.text = exercise.title
cell.previewImage.image = UIImage(named: (exercise.gifName + ".gif"))
cell.selectionSwitch.addTarget(self, action: #selector(self.addRemoveExercise(_:)), for: .valueChanged)
return cell
}
#IBAction func addRemoveExercise(_ sender: UISwitch!) {
let buttonPosition:CGPoint = sender.convert(CGPoint.zero, to:self.tableView)
let indexPath = self.tableView.indexPathForRow(at: buttonPosition)
if(sender.isOn){
customizedSection?.exercises[indexPath!.row] = section!.exercises[indexPath!.row]
}
else{
customizedSection?.exercises[indexPath!.row] = ExerciseModel()
}
}
Your tableView:
import UIKit
class TableViewController: UITableViewController,switchValues {
func changed(_ cell: UITableViewCell, _ mySwitch: UISwitch) {
let index = tableView.indexPath(for: cell)
switchStates[(index?.row)!] = mySwitch.isOn
tableView.reloadData()
}
var switchStates : [Bool] = [false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return switchStates.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyTableViewCell
cell.mySwitch.isOn = switchStates[indexPath.row]
cell.delegate = self
return cell
}
Your cell:
import UIKit
protocol switchValues {
func changed(_ cell:UITableViewCell,_ mySwitch:UISwitch)
}
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var mySwitch: UISwitch!
var delegate:switchValues!
#IBAction func valueChanged(_ sender: UISwitch) {
delegate.changed(self, mySwitch)
}
}

I want to create a signup Form with n number of UITextFields in custom UITableViewCell

I m creating a UITableViewCell which can display n numbers of UITextfields.Please suggest me how to declare these textfields . And also mention how to implement the cellForRowAt function for it.
Heres my UITableViewCell file
import UIKit
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var textlab: UITextField!
func configure(text: String?, placeholder: String) {
textlab.text = text
textlab.placeholder = placeholder
textlab.accessibilityValue = text
textlab.accessibilityLabel = placeholder
}
#IBOutlet weak var underlineLabel: UILabel!
#IBOutlet weak var AlertMessage: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
AND THE VIEW CONTROLLER FOR IT IS AS FOLLOWS:
import UIKit
class CustomViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var blanklabel = ["","","",""]
var textfields = ["First Name","Last Name","Email","Contact Number"]
var alertmsg = ["Please enter your First Name","Please enter your Last Name","Please enter your Email","Please enter your Contact number",]
var textfield = UITextField()
var AlertMessage = UILabel()
#IBAction func nextLabel(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomTableViewCell
return cell
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
return nil
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
}
It's not good idea to do it in UITableView with dynamic cells. Try to use custom view (change your cell class to subclass of UIView) in UIStackView or UITableView with static cells. And set uitextfields as properties in your viewcontroller.

Retrieving the tag from a cell in row in a section [duplicate]

This question already has answers here:
Cannot assign a value of type '[(String)]' to a value of type 'String!'?
(2 answers)
Closed 4 years ago.
enter image description hereI have a tableView with a custom cell. I have added a button to this cell (I have created a UITableViewCell subclass for this cell).
My data is distributed in 3 sections and rows. I want to be able to press the button at any row and pass that row content to the next page. I was able to do all this when I did not have any sections. Here is my code:
import UIKit
class ViewController: UIViewController,UITableViewDataSource {
var menu = ["a", "b", "c"]
#IBOutlet weak var tblview: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// print(menu[section].count)
return menu.count
}
func numberOfSections(in tableView: UITableView) -> Int {
//print(menu.count)
return menu.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! AddItemClassCell
cell.textLabel?.text = menu[indexPath.row]
cell.addBtn.tag = indexPath.row
cell.addBtn.addTarget(self, action: #selector(BtnClicked), for: .touchUpInside)
return cell
}
#objc private func BtnClicked(sender: UIButton) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "NextVC") as! NextVC
vc.loadViewIfNeeded()
//vc.lb.text = menu[sender.indexPath.section][sender.indexPath.row]
vc.lb.text = menu[sender.tag]
self.navigationController?.pushViewController(vc, animated: true)
}
}
Here is the cell class:
import UIKit
class AddItemClassCell: UITableViewCell {
#IBOutlet weak var addBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Cannot assign value of type '[String]' to type 'String?'
If your are using a button on a cell you can use
import UIKit
struct Menu {
let title: String
let innerMenu: [String]
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTV: UITableView!
let menuArr = [
Menu(title: "1", innerMenu: ["a", "b", "c"]),
Menu(title: "2", innerMenu: ["d", "e", "f"]),
Menu(title: "3", innerMenu: ["g", "h", "i"]),
]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTV.delegate = self
myTV.dataSource = self
myTV.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return menuArr.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return menuArr[section].innerMenu.count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let title = UILabel()
title.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 50)
title.text = menuArr[section].title
return title
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : MyCell! = tableView.dequeueReusableCell( withIdentifier: "MyCell") as? MyCell
cell.lbl_Title.text = menuArr[indexPath.section].innerMenu[indexPath.row]
cell.btn_Click.addTarget(self, action: #selector(BtnClicked), for: .touchUpInside)
return cell as MyCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
#objc func BtnClicked(sender:UIButton!){
let view = sender.superview!
let cell = view.superview as! MyCell
let indexPath = myTV.indexPath(for: cell)
print("\(indexPath?.section) - \(indexPath?.row)")
}
}