I want to do a simple thing to my app.
Take a look at my main ViewController:
class Page1: UITableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Shared.instance.employees.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell1
cell.nameLabel.text = Shared.instance.employees[indexPath.row].name
cell.positionLabel.text = Shared.instance.employees[indexPath.row].position
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? Page2,
let indexPath = tableView.indexPathForSelectedRow {
destination.newPage = Shared.instance.employees[indexPath.row]
}
}
}
So, what function do I have to add to show the number of rows as I add more and more itens?
Differences between with and without delegates:
Just implement
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "Total \(Shared.instance.employees.count) rows"
}
If you want to customize the title you have to implement tableView:viewForFooterInSection: and return a view for example:
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 30.0))
label.font = UIFont.boldSystemFont(ofSize: 20.0)
label.textAlignment = .center
label.text = "Total \(Shared.instance.employees.count) rows"
return label
}
Side-note: Instead of calling Shared.instance.employees multiple times use a temporary variable:
let employee = Shared.instance.employees[indexPath.row]
cell.nameLabel.text = employee.name
cell.positionLabel.text = employee.position
I solved the stuff doing this -> I inserted a simple label below the Prototype Cell, like this:
Then, I just put this on viewDidLoad:
footerLabel.text = String(Shared.instance.employees.count) + " employees"
By the way, thanks Mr vadian for your help.
Related
I am new in swift and I am using IQKeyboardManagerSwift library for textfield and textview. I am not able to send Indexpath from tableview to selector function. My code is like this
TableViewCell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TimeSheetTableViewCell", for: indexPath) as? TimeSheetTableViewCell else {
return UITableViewCell()
}
cell.txtTimeSheet.text = arrcheck[indexPath.row]
cell.txtTimeSheet.keyboardToolbar.doneBarButton.setTarget(self, action: #selector(doneButtonClicked))
return cell
}
#objc func doneButtonClicked(_ sender: Any) {
print("Done")
}
I want Indexpath of tableview in donebuttonClick function. Is it possible.
Thanks in Advance!
try this code, just copy and paste
set UITextFieldDelegate, UITextViewDelegate
var strViewFooter = ""
var textFieldIndexPath = IndexPath()
func numberOfSections(in tableView: UITableView) -> Int {
arraycheck.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
func textViewDidEndEditing(_ textView: UITextView) {
strViewFooter = textView.text
}
func textFieldDidEndEditing(_ textField: UITextField) {
let cell: UITableViewCell = textField.superview?.superview as! UITableViewCell
let table: UITableView = cell.superview as! UITableView
textFieldIndexPath = table.indexPath(for: cell)!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "TimeSheetTableViewCell", for: indexPath) as? TimeSheetTableViewCell else {
return UITableViewCell()
}
cell.txtTimeSheet.keyboardToolbar.doneBarButton.setTarget(self, action: #selector(doneButtonClicked))
return cell
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let vw = UIView()
vw.backgroundColor = UIColor.clear
let titleLabel = UITextView(frame: CGRect(x:10,y: 5 ,width:350,height:150))
titleLabel.backgroundColor = UIColor.clear
titleLabel.font = UIFont(name: "Montserrat-Regular", size: 12)
titleLabel.text = arrayFootter[section]
titleLabel.tag = section
vw.addSubview(titleLabel)
titleLabel.keyboardToolbar.doneBarButton.setTarget(self, action: #selector(donebuttonClickedOnView))
return vw
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 50
}
#objc func doneButtonClicked(_ sender: Any) {
print(textFieldIndexPath)
print(textFieldIndexPath.row)
print(textFieldIndexPath.section)
}
#objc func donebuttonClickedOnView(_ sender: UIBarButtonItem){
arrayFootter.remove(at: sender.tag)
arrayFootter.insert(strViewFooter, at: sender.tag)
print(sender.tag)
}
first make a variable like this in your app that you can use it in cellForRowAt,
like this:
var appIndexPathRow = Int()
then put this code in your cellForRowAt:
appIndexPathRow = indexPath.row
Those code would work if you got only 1 section in your tableview, if you have more than 1 I should give you another code!
after all you can print your index in button action! have fun
PS: I just gave you what you put in your question, but i would use it in didSelectRowAt instead of cellForRowAt if it was my project!
Get indexpath on click Button.
#objc func doneButtonClicked(_ sender: Any) {
let tag = sender.tag
let index = IndexPath(row: tag, section: 0)
let cell = tableView.cellForRow(at: index) as! tableView
}
How would I move cells from my first section in my tableview to the second section after the users selects the button?
This establishes my tableview.
#IBOutlet weak var goalTableView: UITableView!
let sections: [String] = ["Today:", "History:"]
var goals: [[String]] = [["Goal 1", "Goal 2", "Goal 3"], [""]]
override func viewDidLoad() {
super.viewDidLoad()
In my viewdidload I would add a connection from my button to my view controller, but would I have to develop a function here to move the selected cell to the new section?
let headerView = UIView()
goalTableView.tableHeaderView = headerView
headerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 5)
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return goals[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TodayGoalViewCell_1", for: indexPath) as? GoalTableViewCell
cell?.goalLabel.text = goals[indexPath.section][indexPath.row]
cell?.cellDelegate = self
cell?.index = indexPath
return cell!
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return goals.count
}
}
extension ViewController: GoalTableView {
func selectGoalButton(index: Int) {
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Only move cell from the 1st section
if indexPath.section == 0 {
// Append the selected element to the second array
goals[1].append(goals[0][indexPath.row])
// Remove the selected element from the first array
goals[0].remove(at: indexPath.row)
tableView.reloadData()
}
}
I try to make a multi section UITableView. I get it work if I only add two strings into my "overview" array. But when I try to call my class "Player" and "Comepetitions" I don't make it work. I have checked and both classes have elements.
//My player and Comepetitions class
var comepetition = [Comepetitions]() //Tävlingar
var players = [Player]()//Spelare
let sections = ["Tävlingar","Spelare"]
//here I want to replace my strings to my classes (player and Comepetitions class)
var overview = [[Player](),[Comepetitions]()] as [Any]
override func viewDidLoad() {
super.viewDidLoad()
print(overview)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (overview[section] as AnyObject).count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ConconfirmCell", for: indexPath)
cell.textLabel?.text = overview[indexPath.section] as? String
cell.textLabel?.textColor = UIColor.white
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 20.0)
return cell
}
//All Information how wants to follow the Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//Segue for start a new game
if segue.identifier == "startNewGameSegue" {
let destVC=segue.destination as! GameViewController
destVC.competitions = comepetition as [Comepetitions]
destVC.players = players
}
}
}
This code works!
var comepetition = [Comepetitions]() //Tävlingar
var players = [Player]()//Spelare
let sections = ["Tävlingar","Spelare"]
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (section == 0) {
return comepetition.count
} else {
return players.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ConconfirmCell", for: indexPath)
if (indexPath.section == 0) {
cell.textLabel?.text = comepetition[indexPath.row].comepetitionsOption
}else{
cell.textLabel?.text = players[indexPath.row].name
}
cell.textLabel?.textColor = UIColor.white
cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 20.0)
return cell
}
//All Information how wants to follow the Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//Segue for start a new game
if segue.identifier == "startNewGameSegue" {
let destVC=segue.destination as! GameViewController
destVC.competitions = comepetition as [Comepetitions]
destVC.players = players
}
}
}
I think it's because of this line, it's optional and you should unwrap it but in the code you post there is no optional checking.
var comepetition = [Comepetitions?]()
And could you add the code that has problem because with code you post here the is no way to know witch is going to be section and witch is the items for that section.
Hope this will helps.
I'm new to Swift, and I am currently creating a diary app that asks the user questions. I'm storing the user's input like this:
dict = ["date": ["question1": "answer", "question2": "answer"]]
Now I need to display this data back to the user in a tableview, where "date" is a title and "question1" is the description.
I've looked online, but answers seem to reference "indexPath.row" for inputting information into a cell, but since this is a dictionary of strings, I can't do that.
Thank you for your help!
Rather than using an array of dictionaries, you should consider using objects that better represent your data.
struct Question: {
let question: String
let answer: String
}
struct DiaryDay {
let date: Date // Note this is a Date object, not a String
let questions: [Question]
}
then you have
let diaryDays = DiaryDay(date: <date>, questions:
[Question(question: "question1": answer: "answer"),
Question(question: "question2": answer: "answer")])
while there's a bit more code, going forward you'll find it easier to see what's happening.
It looks like you should have a section per diary day…
override func numberOfSections(in tableView: UITableView) -> Int {
return diaryDays.count
}
and then one row per question…
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let diaryDay = diaryDays[section]
return diaryDay.questions.count
}
and then configure your cell…
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeue cell
let diaryDay = diaryDays[indexPath.section]
let question = diaryDay.questions[indexPath.row]
cell.question = question
return cell
}
and show the date in the section header…
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let diaryDay = diaryDays[section]
return // formatted diaryDay.date
}
you will have to do a little preparation before you can display data from the dictionary type you are using. Also remember the dictionary is not order list so which order the data will be printed solely depends on system. One approach would be the following
var data = ["date1":["q1":"A1","q2":"A2","q3":"A3"],"date2":["q1":"A1","q2":"A2","q3":"A3"]] . //This is data from your example
var displayableData = [(title: String, qAndA: [(question: String, answer: String)])]() //this is what we will be needing
override func viewDidLoad() {
super.viewDidLoad()
//convert the whole dictionary to tuple
displayableData = data.map { ($0.key, $0.value.map{ ($0.key, $0.value)})}
//here we have converted the dictionary to what we need
}
override func numberOfSections(in tableView: UITableView) -> Int {
return displayableData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return displayableData[section].qAndA.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 55.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let currentQA = displayableData[indexPath.section].qAndA[indexPath.row]
cell.textLabel?.text = "\(currentQA.question) -> \(currentQA.answer)"
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30.0
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 30.0))
view.backgroundColor = UIColor.lightGray
let label = UILabel(frame: CGRect(x: 10, y: 0, width: view.bounds.width - 20, height: 30.0))
label.text = displayableData[section].title
view.addSubview(label)
return view
}
You can use the dictionary as it is without changing
You should sort before use, remember
let dict = ["date": ["question1": "answer", "question2": "answer"]]
Number of sections
override func numberOfSections(in tableView: UITableView) -> Int {
return dict.count
}
Title of the header
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Array(dict)[section].key
}
Number of rows in section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let key = Array(dict)[section].key
return dict[key]?.count ?? 0
}
Cell for row at
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let key = Array(dict)[section].key
if let questionsDict = dict[key] {
let keyValue = Array(questionsDict)[indexPath.row]
print("Question: \(keyValue.key), Answer: \(keyValue.value)")
}
return cell
}
You can try out using map. here Dictionary converts into Array of Dictionary.
let dict = ["date": ["question1": "answer", "question2": "answer"]]
if let value = dict["date"] {
let v = value.map {
["question": $0.key, "answer": $0.value]
}
debugPrint(v)
}
I have a UITableViewController, which has a custom cell that I want to display an image and labels. screenshots can explain my problem very well, it looks like this
.
And when I select any cell it looks like
In tableviewcontroller cell is not visible in proper shape according to constraints
here is my custom cell with autolayout constraints
How I can fix this issue? ... I created this tableviewcontroller programmatically without using storyboard.
here is code sample of data source and delegates of tableviewcontroller
override func numberOfSections(in tableView: UITableView) -> Int {
var numOfSections: Int = 0
let count = conversations.count
if count > 0 {
// tableView.separatorStyle = .none
numOfSections = 1
tableView.backgroundView = nil
}
else
{
let frame = CGRect(x: 0,
y: 0,
width: tableView.bounds.size.width,
height: tableView.bounds.size.height)
let noDataLabel: UILabel = UILabel(frame: frame)
noDataLabel.text = "You don't have any messages. 🙃"
noDataLabel.textColor = UIColor.black
noDataLabel.textAlignment = .center
tableView.backgroundView = noDataLabel
tableView.separatorStyle = .none
}
return numOfSections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return conversations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "inboxCell", for: indexPath) as! InboxCell
cell.conversation = conversations[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let uids = conversations[indexPath.row].conversationUseruids
for uid in uids{
if uid == Account.account.user.uid{
}
else{
User.getUser(with: uid, completion: { (user) in
self.selectedUser.append(user!)
})
}
}
tableView.deselectRow(at: indexPath, animated: true)
let index = indexPath.row as Int
messageVC.conversationIndex = index
messageVC.conversation = self.conversations[index]
navigationController?.pushViewController(messageVC, animated: true)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
it happen because your image not have upper lower constraint if not working than let me know