Need help adding a section to TableViewController array - swift

I want to add a third section to the this UITableViewController. I've tried this :
var listOfCauses:[[String]] = [
["Causes", "", ""],
["Cause 1" , "small descript", "links"],
["Cause 2", "small descript", "links"]
]
When I run the application table view the links subheading doesn't show. How do I fix this? Thanks in advance! Here is my full code for the UITableViewController below:
import UIKit
class CausesTableViewController: UITableViewController {
// I want to add the third section to this array
var listOfCauses:[[String]] = [
["Causes", ""],
["Cause 1" , "small descript"],
["Cause 2", "small descript"]
]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOfCauses.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell( withIdentifier: "cellIdentifier")
if cell == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier")
}
cell?.textLabel?.font = UIFont.boldSystemFont(ofSize: 23)
cell!.textLabel!.text = listOfCauses[indexPath.row][0]
cell?.detailTextLabel?.textColor = .darkGray
cell?.detailTextLabel?.font = UIFont.systemFont(ofSize: 17.0)
cell!.detailTextLabel!.text = listOfCauses[indexPath.row][1]
return cell!
}
}

Update these methods
override func numberOfSections(in tableView: UITableView) -> Int {
// return the number of sections
return listOfCauses.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOfCauses[section].count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell( withIdentifier: "cellIdentifier")
if cell == nil {
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier")
}
cell?.textLabel?.font = UIFont.boldSystemFont(ofSize: 23)
cell!.textLabel!.text = listOfCauses[indexPath.section][indexPath.row]
cell?.detailTextLabel?.textColor = .darkGray
cell?.detailTextLabel?.font = UIFont.systemFont(ofSize: 17.0)
cell!.detailTextLabel!.text = listOfCauses[indexPath.row][1]
return cell!
}

Related

Multiple headerview in tableview in swift

I want to create 3 headers in the tableview given in the images and 8 students in each row, my code is as follows
Screenshot of the example
class ViewController: UIViewController {
var schoolOfList: [Any] = [
[["school": ["VIP", "Bright International", "Motherland"]],
[["student1": ["Chirag", "Akshay", "Shailesh", "Vishal", "Mehul", "Vinod", "Mukesh", "Darshan"]],
["student2": ["Manjari", "Kairav", "Abhimanyu", "Akshara", "Arohi", "Neel", "Naksh", "Naman"]],
["student3": ["Paritosh", "Anuj", "Kavya", "Samar", "Vanraj", "Kinjal", "Anupama", "Riyan"]]]]]
#IBOutlet weak var mytableview : UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> (Int) {
return schoolOfList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath)
cell.textLabel?.text = schoolOfList["school"] as! [String]indexPath.row
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerview = UIView(frame: CGRect(x:0,y:0,width:self.mytableview.frame.width,height:50))
headerview.backgroundColor = .green
let lable = UILabel(frame: CGRect(x:0,y:0,width:self.mytableview.frame.width,height:50))
lable.textAlignment = .center
lable.text = (schoolOfList["school"]as!String)
headerview.addSubview(lable)
return headerview
}

SWIFT / UIKit Footer text displaying over dynamic tableViewCell

I have a UITableViewcontroller setup with just two cells. The footer text is displaying over the last cell.
Strangely I have other controllers with practically the same setup and code and where the footer is showing as expected.
I have tried tried changing the style group / inset etc.
Any ideas appreciated. Thanks
import UIKit
class LanguagesTableViewController: UITableViewController {
var checked = [Bool]()
var choices = ["English","French"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.allowsMultipleSelection = false
let defaults = UserDefaults.standard
checked = defaults.array(forKey: "Language") as? [Bool] ?? [true, false]
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateSwitchState()
tableView.reloadData()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "languageChoiceCell", for: indexPath)
cell.textLabel?.text = choices[indexPath.row]
if !checked[indexPath.row] {
cell.accessoryType = .none
} else if checked[indexPath.row] {
cell.accessoryType = .checkmark
}
return cell
}
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 choices.count
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if checked[indexPath.row] {
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableView.ScrollPosition.none)
}
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return Constants.languagesFooterText
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// If we are selecting a row that is already checked we do nothing
guard !checked[indexPath.row] else { return }
// Reset all checked state.
checked = [Bool](repeating: false, count: choices.count)
// And set the current row to true.
checked[indexPath.row] = true
if let cell = tableView.cellForRow(at: indexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
checked[indexPath.row] = false
} else {
cell.accessoryType = .checkmark
checked[indexPath.row] = true
}
}
updateSwitchState()
}
// did ** DE ** Select
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
checked[indexPath.row] = false
} else {
cell.accessoryType = .checkmark
checked[indexPath.row] = true
}
}
updateSwitchState()
}
func updateSwitchState() {
let defaults = UserDefaults.standard
defaults.set(checked, forKey: "Language")
}
}
You should set a height on your footer view. You can do this by calling tableView(:heightForFooterInSection:) and returning UITableView.automaticDimension.
As you are inheriting from UITableViewController you can do it in the following way
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
UITableView.automaticDimension
}
This will give you the following result:

Why does UITableView show the same view for each cell?

I have been trying to implement a UISegmentedControl in the first cell of a UITableView and it has worked however it shows for each cell following the first one. How do I fix this
import UIKit
class InfoTableViewController: UITableViewController {
convenience init() {
self.init(style: UITableView.Style.grouped)
}
var image: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 5
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
if indexPath.row == 0 {
let genderItems = ["Male", "Female"]
let genderControl = UISegmentedControl(items: genderItems)
genderControl.addTarget(self, action: #selector(genderChanged), for: .valueChanged)
cell.contentView.addSubview(genderControl)
genderControl.translatesAutoresizingMaskIntoConstraints = false
genderControl.centerXAnchor.constraint(equalTo: cell.centerXAnchor).isActive = true
genderControl.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
}
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0{
return view.frame.height/3
}
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let imageView: UIImageView = UIImageView()
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFit
imageView.image = self.image
return imageView
}
return nil
}
#objc func genderChanged(){
}
}
Solution #1
Remove this
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 5
}
and return 5 here
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 5
}
Solution #2
Replace
if indexPath.row == 0 {
to
if indexPath.section == 0 {
in both options you should implement else for that if to return the other needed cell
also move this line to viewDidLoad
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")

CollectionView Inside TableView

I have a CollectionView in TableViewController cell the tableViewcontains 3 sections each section is a different category. How I can pass different data in each section. Like Netflix app
In UICollectionViewController file
import UIKit
import Alamofire
class HomeViewController: UITableViewController, MovieDataDelegate {
let tableViewHeaderIdentifier = "FeaturedTableHeader"
var homePresenter : HomePresenter!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let headerNib = UINib(nibName: "FeaturedUITableViewHeaderView", bundle: nil)
tableView.register(headerNib, forHeaderFooterViewReuseIdentifier: tableViewHeaderIdentifier)
homePresenter = HomePresenter()
homePresenter.delegate = self
homePresenter.fetchData()
homePresenter.fetchImageData()
}
func arrayOfMoviesNames(names: [String]) {
//print(homePresenter.homeData.moviesNamesArray)
tableView.reloadData()
}
func arrayOfPosters(path: [String]) {
//print(homePresenter.homeData.posterPathsArray)
}
//MARK: - Home UI table
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "featuredCell", for: indexPath) as! FeaturedTableViewCell
cell.homeCollectionView.dataSource = self
return cell
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: tableViewHeaderIdentifier) as! FeaturedUITableViewHeaderView
switch section {
case 0:
headerView.isHidden = true
case 1:
headerView.catagoryLabel.text = "Popular Movies"
case 2:
headerView.catagoryLabel.text = "Celebs"
default:
headerView.catagoryLabel.text = "" as String
}
return headerView
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 0
}
return 35
}
override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat {
return 12
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? FeaturedTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
}
}
//MARK: - collectionView
extension HomeViewController : UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return homePresenter.homeData.moviesNamesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "homeCollectionCell", for: indexPath) as! HomeCollectionViewCell
cell.posterImage.image = UIImage(named: "Aladdin")
cell.movieName.text = "coco"
return cell
}
}
In UITableViewCell file
import UIKit
class FeaturedTableViewCell: UITableViewCell {
#IBOutlet weak var homeCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let collectionNib = UINib(nibName: "HomeCollectionViewCell", bundle: nil)
homeCollectionView.register(collectionNib, forCellWithReuseIdentifier: "homeCollectionCell")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension FeaturedTableViewCell {
func setCollectionViewDataSourceDelegate<D: UICollectionViewDataSource & UICollectionViewDelegate>(_ dataSourceDelegate: D, forRow row: Int) {
homeCollectionView.delegate = dataSourceDelegate
homeCollectionView.dataSource = dataSourceDelegate
homeCollectionView.tag = row
homeCollectionView.reloadData()
}
}
screenshot of app
I want to show diffrent image and text for each section of tabelview
Create a struct Movie and create an array of tuple in the view controller. In tuple add a category title and an array of related movies. In table view data source methods use the main array and in collection view data source methods use the movies array from the corresponding tuple. Set the current tuple/section index as the collectionView tag. And get the appropriate movies array in the collection view data source methods.
//HomeViewController
class HomeViewController: UITableViewController {
struct Movie {
var name: String
var image: UIImage?
//other details
}
var movieDetails:[(title:String, movies:[Movie])] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(FeaturedCell.self, forCellReuseIdentifier: "FeaturedCell")
movieDetails = [(title: "MoviesDB", movies: [Movie(name: "a", image: UIImage(named: "a")),
Movie(name: "b", image: UIImage(named: "b")),
Movie(name: "c", image: UIImage(named: "c"))]),
(title: "Popular Movies", movies: [Movie(name: "d", image: UIImage(named: "d")),
Movie(name: "e", image: UIImage(named: "e")),
Movie(name: "f", image: UIImage(named: "f"))]),
(title: "Celebs", movies: [Movie(name: "g", image: UIImage(named: "g")),
Movie(name: "h", image: UIImage(named: "h")),
Movie(name: "i", image: UIImage(named: "i"))])]
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return movieDetails.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return movieDetails[section].title
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturedCell") as? FeaturedCell ?? FeaturedCell(style: .default, reuseIdentifier: "FeaturedCell")
cell.collectionView.tag = indexPath.section
cell.collectionView.delegate = self
cell.collectionView.dataSource = self
return cell
}
}
extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return movieDetails[collectionView.tag].movies.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCell", for: indexPath) as? HomeCell ?? HomeCell()
let movie = movieDetails[collectionView.tag].movies[indexPath.item]
cell.posterImage.image = movie.image
cell.movieName.text = movie.name
return cell
}
}
//FeaturedCell
class FeaturedCell: UITableViewCell {
var collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
collectionView.register(HomeCell.self, forCellWithReuseIdentifier: "HomeCell")
collectionView.translatesAutoresizingMaskIntoConstraints = false
addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
}
}
//HomeCell
class HomeCell: UICollectionViewCell {
let posterImage = UIImageView()
let movieName = UILabel()
//...
}
Use both UITableView data source and UICollectionView data source methods.
Set 3 sections in UITableView with only one cell for every section.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Your cell with UICollectionView inside
let cell = tableView.dequeueReusableCell(withIdentifier: "YOUR_TABLE_VIEW_CELL_IDENTIFIER", for: indexPath)
// Set UICollectionViewDataSource, also add data source methods in your class, look at next code block
cell.collectionView.dataSource = self
return cell
}
// Header for each section,
func tableView(_ tableView: UITableView,
titleForHeaderInSection section: Int) -> String? {
if (section == 0) {
return nil
} else if (section == 1) {
return "Popular movies"
} else if (section == 2) {
return "Celebs"
}
}
// UICollectionViewDataSource methods
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1 // only one section for each UICOllectionView
}
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
// return here number of items in each UICollectionView
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YOUR_COLLECTION_CELL_IDENTIFIER", for: indexPath)
// set real data for each UICollectionCell here
cell.label = "COCO"
return cell
}
If you want to

How to make label or image dynamic in tableviewcell?

I want to make tableview cell have dynamic label or image in it. I don't want to loop add subview to content view of tableview cell because it will run slow when you scroll. So can anyone help me please? Like this image:
My code is;
Without knowing the context of your code, something like this can work:
NOTE This will work on iOS <= 8
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var TableVC: UITableView!
let elements = ["item1 item2 item3","item1 item2", "item1"]
override func viewDidLoad() {
super.viewDidLoad()
self.TableVC.delegate = self
self.TableVC.dataSource = self
self.TableVC.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// 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.
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.numberOfLines = 0
cell.textLabel?.attributedText = addTextToAttribute(text: elements[indexPath.item])
return cell
}
func addTextToAttribute(text : String) -> NSMutableAttributedString {
let mutString = NSMutableAttributedString()
let s = text.components(separatedBy: .whitespaces)
let attr: [String: AnyObject] = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 20)]
for text in s {
mutString.append(NSAttributedString(string: "-" + text + "\n", attributes: attr))
}
return mutString
}
}