I not find what is my problem.
I need to give space between one cell and another.
I wrote self.tableView Storyline.delegate = self because I read that this could be the problem, but not know if it is correct.
This is my code:
class ClassName: UIViewController, UITableViewDataSource, UITabBarControllerDelegate, UITableViewDelegate {
public var notifications: [APINotification] = []
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
tableViewStoryline.rowHeight = UITableViewAutomaticDimension
tableViewStoryline.estimatedRowHeight = 140
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
self.notifications = []
self.getLastNotifications()
APIAuth.shared.count_badge = 0
self.tabBarController?.tabBar.items![0].badgeValue = nil
}
public func getLastNotifications() {
let req = Notification()
req.getLastNotifications(onComplete: {events in
self.notifications = events
DispatchQueue.main.async(execute: {
self.tableViewStoryline.delegate = self
self.tableViewStoryline.dataSource = self
self.tableViewStoryline.sectionHeaderHeight = 10
self.tableViewStoryline.reloadData()
})
})
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// There is just one row in every section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.notifications.count > 4 {
return 4
} else {
return self.notifications.count
}
}
// Set the spacing between sections
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell = tableView.dequeueReusableCell(withIdentifier: "controller")! as UITableViewCell
titleLbl.text = notifications[indexPath.row].title
bodyLbl.text = notifications[indexPath.row].description
typeLbl.text = notifications[indexPath.row].type
return cell!
}
}
Does anyone have any idea what the problem is?
Is there some code missing?
Thanks!
I think this is what you want:
func numberOfSections(in tableView: UITableView) -> Int {
if self.notifications.count > 4 {
return 4
} else {
return self.notifications.count
}
}
// There is just one row in every section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
Then you have to change also cellForRowAt to take this into account.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell = tableView.dequeueReusableCell(withIdentifier: "controller")! as UITableViewCell
titleLbl.text = notifications[indexPath.section].title
bodyLbl.text = notifications[indexPath.section].description
typeLbl.text = notifications[indexPath.section].type
return cell!
}
Instead of having one section with notifications.count rows, you want notifications.count sections and each section with one row. Now setting 10 points as height for section header will make cells appear as having spaces between them.
There are some other options that you can consider, see my other answer.
you are using wrong delegate function.
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
is used for the hieght of header not for height of cell.
use func tableView(UITableView, heightForRowAt: IndexPath)
you will get correct sized cells.
Hope this helps!
Related
import UIKit
private let reuseableIdentifier = "cell"
class TableViewController: UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self,forCellReuseIdentifier: reuseableIdentifier)
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseableIdentifier, for: indexPath )
return cell
}
}
So this is my code but at the dequereuseableCell for: indexPath it showing error like can not find indexPath in scope.
You need to return a number greater than 0 in the method of numberOfSections and numberOfRowsInSection
You need to return a cell in the method of cellForRowAt indexPath
import UIKit
private let reuseableIdentifier = "cell"
class TableViewController: UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self,forCellReuseIdentifier: reuseableIdentifier)
}
override func numberOfSections(in tableView: UITableView) -> Int {
// return number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return number of rows in sections
return 10
}
// add method
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseableIdentifier, for: indexPath )
return cell
}
}
You are still missing one method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeue your cell here
}
the method you use should read:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return the number of elements to show here
}
documentation
tutorial
Interface:
Interface in debugger:
Here is configuration of tableview
private func configureTableView(){
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
// tableView.rowHeight = UITableView.automaticDimension
tableView.register(DishCell.self, forCellReuseIdentifier: "dishCell")
// tableView.sectionHeaderHeight = UITableView.automaticDimension
}
Here is tableView extensions
extension MenuViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 380
}
return 48
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
return 122
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableView.automaticDimension
}
}
extension MenuViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.dishes.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.dishes[section].count
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let dishType = viewModel.dishTypes[section]
if section == 0 {
let restaurant = viewModel.restaurant
return FirstMenuHeader(restaurant: restaurant, dishType: dishType)
}else{
return DefaultMenuHeader(dishType: dishType)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dishCell") as! DishCell
let dish = viewModel.dishes[indexPath.section][indexPath.row]
cell.set(dish: dish)
return cell
}
}
Just to clarify DishCell, FirstMenuHeader and DefaultMenuHeader look well if you put them outside of UITableview. And they have constraints that define their height. However their height is dynamic and depends on amount of line of text.
Problem was in dishCell.I made constraints with view, while I had to make constraints with contentView.
I have rewrote my constraints and problem was resolved.
When I try to run my code, the cellForRowAtIndexPath function does not run for some reason.
The numberOfSections function works perfectly. I was thinking it was the dataSource/delegate function or a problem with the cell.
Would really appreciate finding solution to this problem.
import UIKit
class MoviesTableViewController: UITableViewController {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
MovieController.getAllMovies(name: "blue") { (sucess) in
if sucess {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return MovieController.movies.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 148
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "movieCell", for: indexPath) as! MoviesTableViewCell
let movie = MovieController.movies[indexPath.row]
cell.movieRating.text = String(movie.vote_average)
cell.movieRating.text = movie.overview
cell.movieTitle.text = movie.title
return cell
}
Print Debugging
override func numberOfSections(in tableView: UITableView) -> Int {
print("Number of section called")
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("Number of rows in section called")
print("Movies count: ", MovieController.movies.count)
return MovieController.movies.count
}
If Number of section called not printed to console: you have issue with tableView and It's DataSource
else if Movies Count: 0: tableView datasource working well and It's your MoviewController.movies issue. Check your MovieController
For the next step I need to see MoviewController content.
First you don't need to make tablevew.delegate = self in UItableViewController its already known , but this not the issue
You should make sure that your datasource MovieController.movies
have data before you call , just print movies before you call
self.tableview.reloadData()
There are number of cases which prevent your cellForRowAt to be called.
If your array MovieController.movies has 0 objects/elements, which you have return as MovieController.movies.count in your numberOfRowsInSection.
If you have placed your UITableView in storyboard or xib and because of any reason your UITableView don't get enough height to show your content in that case also your cellForRowAt will never be called. In most of the cases the height is 0.
I have been reading similar questions and until now neither has solved this error or I have not found it.
I have a TableView and I need the table to have a specific number of rows.
Now it works with a count of notifications from a array. In this array, I keep the notifications that come from the server.
But I want that if this array count is greater than 40, the rows are 40 and they not are the count of the array.
This is my code:
class ClassName: UITableViewController, UITabBarControllerDelegate {
public var notifications: [APINotification] = []
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.delegate = self
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
self.notifications = []
self.getLastNotifications()
APIAuth.shared.count_badge = 0
self.tabBarController?.tabBar.items![0].badgeValue = nil
}
public func getLastNotifications() {
let req = Notification()
req.getLastNotifications(onComplete: {events in
self.notifications = events
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return self.notifications.count
}
// There is just one row in every section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// Set the spacing between sections
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let event = self.notifications[indexPath.section]
let cell = tableView.dequeueReusableCell(withIdentifier: "controller", for: indexPath) as! Controller
cell.bodyLbl.text = event.description
cell.typelbl.text = event.type
cell.typelbl.sizeToFit()
cell.titleLbl.text = event.title
cell.subjectLbl.text = event.subject?.name
return cell
} }
Thanks for your help!
You can change this method to :
override func numberOfSections(in tableView: UITableView) -> Int {
return self.notifications.count > 40 ? 40 : self.notifications.count
}
This will show as many rows as you got from your notification but if it's greater than 40 it will display only 40. To make it display 40 all the time just put return 40 instead but this may crash your app it the array will contain less items than 40.
Ps you display 40 sections no rows to change it to rows instead you need to chance your code to:
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.notifications.count > 40 ? 40 : self.notifications.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let event = self.notifications[indexPath.row]
...
}
There are several ways to achieve this:
Simple and consice:
return min(self.notifications.count, 40)
A Swifty approach:
guard self.notifications.count < 40 else {
return 40
}
return self.notifications.count
An alternative more verbose version:
return self.notifications.count < 40 ? self.notifications.count
A different more simple version:
if self.notifications.count > 40 {
return 40
} else {
return self.notifications.count
}
Use which ever version you feel best suits the purpose.
I would probably go for 1 or 2 if I felt like being all Swifty (is that even a word).
Try the following code:
// There is just one row in every section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.notifications.count > 40{
return 40
}
return self.notifications.count
}
To limit the maximum number of sections, just check the array size:
override func numberOfSections(in tableView: UITableView) -> Int {
var count = self.notifications.count
if (count > 40) {
count = 40
}
return count
}
I have a problem that I want to show a tableview, but separated in sections by the "status" of each item. I know how to do it with a simple string array, but I can't get to make this work with a class (Aluno) array, here's my code so far:
import UIKit
class DeliveriesTVC: UITableViewController {
let sections = ["Delivered", "Not Delivered"]
var studentList: [Array<Student>] = [[], []]
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...5{
studentList[0].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Delivered"))
}
for i in 6...10{
studentList[1].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Not Delivered"))
}
self.title = "Deliveries"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cellEntrega = tableView.dequeueReusableCell(withIdentifier: "EntregaCell", for: indexPath) as? EntregaCell {
let entregaCell = studentList[indexPath.section][indexPath.row]
// here i call a function in my TableViewCell class that update the cell itself
cellEntrega.updateAlunoUI(Aluno: entregaCell)
return cellEntrega
} else {
return UITableViewCell()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listaAlunos[section].count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
}
In the output, i just get the "first section" showing, and without a name, even with me setting the name of each section and the number of sections. I've looked everywhere but i couldn't find a solution.
Your numberOfSections and titleForHeader methods are wrong, it should be
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
Additionally, you should return self.sections.count instead of return 2 in numberOfSections being hardcoded as in case you add another object to the array, you will have to change the 2 to whatever elements the array has now.
For your numberOfSectionInTableView function, shouldn't it be override func numberOfSectionsInTableView(in tableView: UITableView) -> Int {
return 2
} with a in in front of the tableView: UITableView?
I don't see where you connect your UITableView's delegate and datasource.
Here is a tutorial to show your about using UITableView.
Take a look at "Basic Table View" - "Step 3: Set the datasource and delegate"