I am making a simple client invoice list using a tableView with custom labels in each row. at the top you click the plus sign. This takes you to a second page where you type in your clients name. you hit save and it should add it to the label in the first view controller. I cannot get this to work.
my tableview storyboard has the file called ViewController.swift - in it
import UIKit
var invoiceList = [""]
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var clientTableView: UITableView!
#IBOutlet var clientLabel: UILabel!
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return invoiceList.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "clientItem", for: indexPath) as! UITableViewCell
let ClientName = invoiceList[indexPath.row]
cell.textLabel?.text = [clientInput]
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete
{
invoiceList.remove(at: indexPath.row)
clientTableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
clientTableView.reloadData()
}
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.
}
}
My second storyboard where you type in the text field. File is called AddInvoiceItem.swift. in it -
import UIKit
class AddInvoiceViewController: UIViewController {
var clientTextField:String!
#IBOutlet var clientInput: UITextField!
#IBAction func addItem(_ sender: Any) {
if clientInput.text != ""
{
invoiceList.append(clientInput.text!)
clientInput.text = ""
_ = navigationController?.popViewController(animated: true)
}
}
#IBAction func cancelBtn(_ sender: Any) {
_ = navigationController?.popViewController(animated: true)
}
}
My error keeps happening when I am trying to use the code line
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "clientItem", for: indexPath) as! UITableViewCell
let ClientName = invoiceList[indexPath.row]
cell.textLabel?.text = [clientInput]
return cell
}
The cell.textLabel?.text = [clientInput]
I know this is wrong, but cannot figure it out!
Make a new cell class
class CustomCell: UITableViewCell {
//Make your outlets here, connect the outlets from cell in your storyboard like ClientNameLabel
}
Please select the cell on your Storyboard, and enter the name of your class in this field. In your case it would be CustomCell
then in ViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "clientItem", for: indexPath) as! CustomCell
let ClientName = invoiceList[indexPath.row]
cell.ClientNameLabel.text = ClientName
return cell
}
Related
I'm trying to create an App but I'm struggling with a simple problem: How can I add a delete button to my custom cells?
I've created a NewCocoaTouchClass
I've created my custom design (added also a button for every cell) and provided the Outlets in the TableViewCellController
I managed to implement my custom cell to another viewController
I created a button on my viewController
I'd like that when the user taps on my new button, cell buttons will appear, and then I can delete cells singularly. When I create the IbAction I can't retrieve the cell code because the cell is defined only in my tableViewCode.
Thank in advance
Ps: I also implemented deleting cells by swipe but my custom cell design is incompatible with the standard rectangular delete option (this is awful).
TableViewCellController
import UIKit
class CustomTableTableViewCell: UITableViewCell {
static let identificatore = "CustomTableTableViewCell"
static func nib() -> UINib {
return UINib(nibName: "CustomTableTableViewCell", bundle: nil)
}
#IBOutlet weak var ImmagineCella: UIImageView!
#IBOutlet weak var TestoCella: UILabel!
#IBOutlet weak var Button: 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
}
}
ViewController
import UIKit
class MaterieViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var materie : [String] = ["zoifvdhfdv", "szvzv", "zdvzfv", "zfdvbfdb", "bfzdfb"]
#IBOutlet weak var TableViewMaterie: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
TableViewMaterie.register(CustomTableTableViewCell.nib(), forCellReuseIdentifier: CustomTableTableViewCell.identificatore)
TableViewMaterie.delegate = self
TableViewMaterie.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return materie.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableTableViewCell.identificatore, for: indexPath) as! CustomTableTableViewCell
cell.TestoCella.text = materie[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 67.83
}
#IBAction func EditButton(_ sender: UIButton) {
}
}
This is the code I use in my project
func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String?
{
return "Delete"
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
//Add your code
}
}
You can write with add target
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableTableViewCell.identificatore, for: indexPath) as! CustomTableTableViewCell
cell.TestoCella.text = materie[indexPath.row]
cell. Button.tag = indexPath.row
cell. Button.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside)
return cell
}
func buttonClicked(sender: UIButton) {
let buttonRow = sender.tag
print(buttonRow)
}
I have stuck up with an issue where I have a UITableView with a label and button in each row when the button is clicked from a particular row it will navigate to the next view and it has UITableView with a country list, when selected the country it will popup to the previous view and I want to update the country name with selected row, Could someone guide me how to update it. Below is my code. TIA
FirstViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableCell
let dict = customData[indexPath.row] as? NSObject
cell.lblTitle.text = "Title"
// cell.lblSubTitle.text = ""
cell.selectedButton.tag = indexPath.row
cell.selectedButton.addTarget(self, action: #selector(buttonClick), for: .touchUpInside)
return cell
}
#objc func buttonClick(sender: UIButton){
let customCell = CountryViewController(nibName: nil, bundle: nil)
self.navigationController?.pushViewController(customCell, animated: true)
}
CountryViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CountryCell", for: indexPath) as! CountryTableCell
cell.lblTitle.text = CountryList[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCountry = CountryList[indexPath.row]
self.navigationController?.popViewController(animated: true)
}
You can use delegation pattern:
protocol SelectCountry {
func countrySelected(withName countryName: String)
}
in your FirstViewController.swift conform to that protocol
extension FirstViewController: SelectCountry {
func countrySelected(withName countryName: String) {
// Assign country name to your label here
}
in your CountryViewController.swift make a variable called delegate/anyName you want
var delegate: SelectCountry?
in your buttonClick method
customCell.delegate = self
in your CountryViewController in didSelectRowAt method
delegate?.countrySelected(withName: CountryList[indexPath.row])
your label will be updated with country name you selected in CountryViewController.
NOTE: Names are just placeholders here you can use your own names for protocol/methods
First Controller:
"CountrySelectionDelegate" confirm this delegate in your first controller
Next, Pass/Store your FirstViewController cell selection index.
Go to your Country Controller, Select country, Pass it through "func selectedCountry(country: String,index: Int) {}" , Update your custom Data/Array.
Lastly reload your Table view with updated Custom data.
class FirstViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,CountrySelectionDelegate {
#IBOutlet weak var yourFirstTable: UITableView!
var customData = [Details(title: "Title-1", country: ""),Details(title: "Title - 2", country: ""),]
override func viewDidLoad() {
super.viewDidLoad()
}
func selectedCountry(country: String,index: Int) {
self.customData[index].country = country
yourFirstTable.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return customData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! DetailTableCell
let custInfo = customData[indexPath.row]
cell.yourTitleLabel.text = "Title: " + custInfo.title
cell.yourCountryLabel.text = (custInfo.country.count > 0 ? "Country: \(custInfo.country)" : "Country: ---")
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "CountryViewController") as? CountryViewController
nextVC?.selectedIndex = indexPath.row
nextVC?.delegate = self
self.navigationController?.pushViewController(nextVC!, animated: true)
}
}
CountryViewController:
import UIKit
protocol CountrySelectionDelegate {
func selectedCountry(country: String, index:Int)
}
class CountryViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var countryTable: UITableView!
var selectedIndex: Int = 0
let countryList = ["India","USA","UK","Nepal","Bangladesh","Pakistan","Bhutan"]
weak var delegate: CountrySelectionDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countryList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CountryTableViewCell
cell.countryLabel.text = countryList[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.selectedCountry(country: countryList[indexPath.row], index: selectedIndex)
self.navigationController?.popViewController(animated: true)
}
}
Im trying to load a array of strings in a table view but the view does not recognize the array.
I have an array called Playlists (declared as global on ThirdViewController) with objects from class Playlist. When I use it on every other table view I can access every object and use it on the table view (I'm using it on ThirdViewController), but on AddToPlaylist view I can't use it. I think I'm using correctly the cells and func for table views.
This happens when I press the button "AƱadir" on player view. It should load the table view with the array info.
Here is the project (develop branch): tree/develop
import UIKit
class AddToPlaylist: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var myTableViewPlaylist: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Playlists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "hola", for: indexPath)
cell.textLabel?.text = Playlists[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
Playlists[indexPath.row].songs.append(songName)
performSegue(withIdentifier: "addedSong", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
myTableViewPlaylist.delegate = self
myTableViewPlaylist.dataSource = self
myTableViewPlaylist.reloadData()
}
}
Here is the declaration of Playlists array:
import UIKit
import AVFoundation
var favorites:[String] = []
var Playlists:[Playlist] = []
var selecPlaylist = 0
var firstOpen2 = true
class ThirdViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var myTableView2: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//print(Playlists.count)
return Playlists.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = Playlists[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selecPlaylist = indexPath.row
performSegue(withIdentifier: "segue", sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
myTableView2.delegate = self
myTableView2.dataSource = self
if firstOpen2{
crear()
firstOpen2 = false
}
myTableView2.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func crear(){
let pl1 = Playlist(name: "Prueba")
pl1?.addSong(song: songs[0])
Playlists.append(pl1!)
let pl2 = Playlist(name: "Prueba2")
pl2?.addSong(song: songs[1])
Playlists.append(pl2!)
}
}
let cell = tableView.dequeueReusableCell(withIdentifier: "yourIdentifier") as! UITableViewCell
cell.textLabel?.text = Playlists[indexPath.row].name
return cell
I have created a tableView with two different labels and one textfield. Depending on the indexPath in which is selected the labels will display different text according to the array. I have created a CocoTouch Class file and made it type TableViewCell.
TableViewCell.swift
import UIKit
class Driver_Navigation_TableViewCell: UITableViewCell {
#IBOutlet weak var orderTextField: UITextField!
#IBOutlet weak var adressLabel: UILabel!
#IBOutlet weak var nameLabel: 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
}
}
ViewController.swift
class ViewController: UIViewController, MGLMapViewDelegate, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate {
var allCellsText = [String]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Driver_Navigation_TableViewCell
cell.adressLabel.text = passengersAdress[indexPath.row]
cell.nameLabel.text = passengersName[indexPath.row]
cell.orderTextField.placeholder = "\(indexPath.row + 1)."
return(cell)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as! Driver_Navigation_TableViewCell
cell.orderTextField.tag = indexPath.row
cell.orderTextField.delegate = self // theField is your IBOutlet UITextfield in your custom cell
return cell
}
func textFieldDidEndEditing(textField: UITextField) {
allCellsText.append(textField.text!)
print(allCellsText)
}
}
You cant have duplicate UITableViewDataSource and UITableViewDelegate methods it won't work like that.
Also in your code you have not set the delegate for the textField in both the cellForRowAtIndexPath() methods.
If you want to have two table view in a single controller try the following
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Driver_Navigation_TableViewCell
if tableView == self.tableView1 {
cell.adressLabel.text = passengersAdress[indexPath.row]
cell.nameLabel.text = passengersName[indexPath.row]
cell.orderTextField.placeholder = "\(indexPath.row + 1)."
}
else {
cell.orderTextField.tag = indexPath.row
}
cell.orderTextField.delegate = self
return(cell)
}
Create outlets for the Table View
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 6 years ago.
I'm new to Swift. I have two table view controllers, one with static cells and one with dynamic ones. I basically want to let a user select his marital status on the second table view controller and send his choice back to the first table view controller (and display his selection on the cell "Marital Status"). Here is a screenshot of my storyboard:
Storyboard
Current code on second table view controller:
import UIKit
class SecondTableViewController: UITableViewController {
let maritalStatusArray: [String] = ["Single", "Married"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return maritalStatusArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MaritalStatusCell", for: indexPath)
cell.textLabel?.text = maritalStatusArray[indexPath.row]
return cell
}
}
My guess is that I have to add a segue from the dynamic cell of the second view controller back to the first one. Is that right ?
Supposing this is the way to do it, I have afterwards to update the text of the static label to include the choice made by the user. Any ideas ?
There few ways by which you can implement the callback functionality to pass data.
Delegate
Using Block CallBack
Post Notification
But I would suggest to use delegate which is best way, Post Notification is also a way but I do not want to prefer.
You can use custom delegate to do this:
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SecondViewControllerProtocol {
#IBOutlet weak var userInfoTableView: UITableView!
var userInfoArray: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
userInfoArray = ["Marital Status","Canton","Commune","Religion"]
self.userInfoTableView?.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let userInfoCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
userInfoCell.textLabel?.text = userInfoArray[indexPath.row]
if indexPath.row == 0{
userInfoCell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
}
return userInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewControllerIdentifier") as! SecondViewController
secondVC.statusDelegate = self
self.navigationController?.present(secondVC, animated: true, completion: nil)
}
}
func changeMaritalStatus(type: String){
let maritalStatusCell = userInfoTableView.cellForRow(at: IndexPath(row:0 , section:0))
maritalStatusCell?.textLabel?.text = String("Marital Status: \(type)")
}
}
SecondViewController.swift:
import UIKit
protocol SecondViewControllerProtocol {
func changeMaritalStatus(type: String)
}
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var maritalStatusTableView: UITableView!
var maritalStatusArray: [String] = []
var statusDelegate : SecondViewControllerProtocol? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
maritalStatusArray = ["Single","Married","Divorced"]
self.maritalStatusTableView.register(UITableViewCell.self, forCellReuseIdentifier: "maritalStatuscell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let maritalStatusInfoCell = tableView.dequeueReusableCell(withIdentifier: "maritalStatuscell", for: indexPath)
let infoLabel: UILabel = UILabel.init(frame: CGRect(x: 10, y: 5, width: 250, height: 50))
infoLabel.text = maritalStatusArray[indexPath.row]
maritalStatusInfoCell.addSubview(infoLabel)
return maritalStatusInfoCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
statusDelegate?.changeMaritalStatus(type: maritalStatusArray[indexPath.row])
self.dismiss(animated: true, completion: nil)
}
}
GitHub link:
https://github.com/k-sathireddy/CustomDelegatesSwift
Output:-