SWIFT / UIKit Footer text displaying over dynamic tableViewCell - swift

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:

Related

how to back data from viewcontroller to tableview use delegate

extension SecondViewController: UITableViewDelegate, UITableViewDataSource, EditContactDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ContactTableView
cell.contact = contacts[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newVC = NewViewController()
newVC.nameLabel.text = contacts[indexPath.row].name
newVC.delegate = self
newVC.numberPhoneLabel.text = contacts[indexPath.row].numberPhone
newVC.avatarView.image = contacts[indexPath.row].avatar
self.navigationController?.pushViewController(newVC, animated: true)
}
func editContact(name: String, numberPhone: String) {
var contact:Contact?
let nameEdit = name
let numberEdit = numberPhone
contact?.name = nameEdit
contact?.numberPhone = numberEdit
}
}
My data is not updating at tableview even though delegate worksenter image description here
Make variable selectedIndex and set value on did select method
var selectedIndex = 0
func editContact(name: String, numberPhone: String) {
guard selectedIndex > 0 else { return }
contacts[selectedIndex].name = name
contacts[selectedIndex].numberPhone = numberPhone
tableView.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newVC = NewViewController()
newVC.nameLabel.text = contacts[indexPath.row].name
newVC.delegate = self
newVC.numberPhoneLabel.text = contacts[indexPath.row].numberPhone
newVC.avatarView.image = contacts[indexPath.row].avatar
self.navigationController?.pushViewController(newVC, animated: true)
selectedIndex = indexPath.row
}

Disable users to scroll up in tableView?

Similar to tinder, if a user goes down, I don't want them to be able to go back upwards. How do I do this?
I tried the code below, but it keeps running an error: Index out of range.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! FeedTableViewCell
cell.collectionView.delegate = self
cell.collectionView.dataSource = self
//reloading the tableview
let artist: UserModel
artist = self.userList[indexPath.row]
cell.nameLabel.text = artist.name
cell.passionLabel.text = artist.passion
cell.collectionView.reloadData()
if indexPath.row == 1 {
userList.removeFirst()
}
return cell
}
Refer below code,
You need to store last scroll Content Offset of tableview, when user scroll down, refer scrollViewDidScroll method.
#IBOutlet weak var tableView: UITableView!
var lastContentOffsetY:CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.bounces = false
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuse")
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuse")
return cell!
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.contentOffset.y < self.lastContentOffsetY){
self.tableView.setContentOffset(CGPoint(x:scrollView.contentOffset.x, y: self.lastContentOffsetY), animated: false)
}else{
self.lastContentOffsetY = scrollView.contentOffset.y
}
}

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")

Swift - How can I select multiple rows in tableview without segue

My development environment is swift3, xcode8.
I'm making a list app like Apple's message app.
When I select the list in the table view, I go to the detail page (through the seg) and now I want to implement multiple delete functions, but there's a problem. When I edit mode, I can see the selection window, but if I select that selection window, just go to the detail page.
Maybe before going to the detail page through Seg. I think I should make it a multiple choice. What should I do?
Make sure you conform something like below code;
class TableviewController:UITableViewController{
override func viewDidLoad() {
super.viewDidLoad()
var isMultipleSelectionActive = false
var selectedItems: [String: Bool] = [:]
tableView.allowsMultipleSelectionDuringEditing = true
tableView.setEditing(true, animated: false)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = items.objectAtIndex(indexPath.row)
//add to selectedItems
selectedItems[selectedItem] = true
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let selectedItem = items.objectAtIndex(indexPath.row)
// remove from selectedItems
selectedItems[selectedItem] = nil
}
func getStatusOfSelectedItems() {
for item in selectedItems {
println(item)
}
}
//You should override shouldPerformSegueWithIdentifier and return false if isMultipleSelectionActive is true
override func shouldPerformSegue(withIdentifier identifier: String?, sender: Any?) -> Bool {
if let identifierName = identifier {
if identifierName == "NameOfYourSegueIdentifier" {
if isMultipleSelectionActive {
return false
}
}
}
return true
}
}
This code used to select the multiple row
class TableViewController: UITableViewController
{
var lastSelectedIndexPath = NSIndexPath(forRow: -1, inSection: 0)
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath)
// Configure the cell...
cell.textLabel!.text = "row: \(indexPath.row)"
if cell.selected
{
cell.selected = false
if cell.accessoryType == UITableViewCellAccessoryType.None
{
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.None
}
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let cell = tableView.cellForRowAtIndexPath(indexPath)
if cell!.selected
{
cell!.selected = false
if cell!.accessoryType == UITableViewCellAccessoryType.None
{
cell!.accessoryType = UITableViewCellAccessoryType.Checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.None
}
}
}

Can't un check all cell before check one swift 2

I m using swift 2 and UITableViews and when I press a cell a checkmark appear, but I wan't that only one cell can be checked in my tableview so the other checkmarks will disappear from my tableview. I tried different technics without success. I have a CustomCell with just a label.
Here is my code :
import UIKit
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var tableView: UITableView!
var answersList: [String] = ["One","Two","Three","Four","Five"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return answersList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MyCustomCell", forIndexPath: indexPath) as! MyCustomCell
cell.displayAnswers(answersList[indexPath.row]) // My cell is just a label
return cell
}
// Mark: Table View Delegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Element selected in one of the array list
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark {
cell.accessoryType = .None
} else {
cell.accessoryType = .Checkmark
}
}
}
}
Assuming you've only section here's what you can do
// checkmarks when tapped
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let section = indexPath.section
let numberOfRows = tableView.numberOfRowsInSection(section)
for row in 0..<numberOfRows {
if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: row, inSection: section)) {
cell.accessoryType = row == indexPath.row ? .Checkmark : .None
}
}
}
Fixed code from #SirH to work with Swift 3
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let section = indexPath.section
let numberOfRows = tableView.numberOfRows(inSection: section)
for row in 0..<numberOfRows {
if let cell = tableView.cellForRow(at:IndexPath(row: row, section: section)) {
cell.accessoryType = row == indexPath.row ? .checkmark : .none
}
}
}