Disable users to scroll up in tableView? - swift

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
}
}

Related

How to user userdefaults to open a tableview with last cell pressed on top position

I'm trying that when I use close an app and start it again a tableview put the last cell pressed on the top. I'm able to store the last cell position with the next code and even move to the top position when press the cell. But I don't now how force the table move to that position when the user comes back.The table has only one section. I'm reading several posts but I don't know how to adapt the solution to my code. Please help!
My code is:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UserDefaults.standard.set(indexPath.row, forKey: "celdaPulsada")
let celdaPulsada = UserDefaults.standard.integer(forKey: "celdaPulsada")
tableView.beginUpdates()
tableView.moveRow(at:[0,celdaPulsada], to: [0, 0])
tableView.endUpdates()
}
This is the demo code please modify it according to your requirement
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupView()
scrollTableViewToLastSelectedPosition()
}
private func setupView() {
tableView.dataSource = self
tableView.delegate = self
}
private func scrollTableViewToLastSelectedPosition() {
let celdaPulsada = UserDefaults.standard.integer(forKey: "celdaPulsada")
tableView.scrollToRow(at: IndexPath(row: celdaPulsada, section: 0), at: .top, animated: false)
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Cell No \(indexPath.row + 1)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UserDefaults.standard.set(indexPath.row, forKey: "celdaPulsada")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 50
}
}

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
}

TableView action per item

I have a tableView like this:
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
let names = ["TEXT1", "TEXT2", "TEXT3"]
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewControllerMeer: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
}
}
extension ViewControllerMeer: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
let n = names[indexPath.item]
switch n {
case "TEXT1":
print("s1")
case "TEXT2":
print("s2")
case "TEXT3":
print("s3")
default:
break
}
return cell
}
}
It reads the items from the 'let names', So far so good :) I now want to add some actions because now every item will print 'You tapped me'. I figured something out like
override func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
print("cell1")
} else if indexPath.row == 1 {
print("cell2")
} else if indexPath.row == 2 {
print("cell3")
}
}
The only problem is that it generates an error 'Method does not override any method from its superclass'. So I guess this won't work. What would be a good method to do it?
remove the override in front of func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
And you can either to a big if statement or switch statement to do something with the names or you can do something like:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
switch indexPath.row {
case 0:
//do something
self.shareApp()
case 1:
//do something else
self.writeReview()
default:
break
}
}
I just copied your codes to show you basically if you really want to override tableview functions
class ViewController: UITableViewController {
#IBOutlet var tableView: UITableView!
let names = ["TEXT1", "TEXT2", "TEXT3"]
override func viewDidLoad() {
super.viewDidLoad()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped me!")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
}
}

Inserting a table view row data from another table view?

So I have two table views. MainTableView and SecondaryTableView, The MainTableView has empty rows with no text. A Table view cell is configured though. These rows have the option to delete. The SecondaryTableView rows also have an editing style in which I am using to ADD the selected row into the MainTableView rows.
class MainVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet var mycartableview: UITableView!
var passedcar = String()
override func viewDidLoad() {
super.viewDidLoad()
mycartableview.tableFooterView = UIView(frame: CGRect.zero)
}
var diynames: [String] = ["a","b","c"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return diynames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let diyname = diynames[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "mycarcell") as! mycarcell
cell.mycartitle.text = diyname
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
diynames.remove(at: indexPath.row)
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
}
}
SecondaryVC code:
class MainVC: UIViewController, UITableViewDelegate, UITableViewDataSource{
let names = ["aa","ba","ca","da","ea",]
#IBOutlet var tableview: UITableView!
#IBOutlet var slctedcar: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.tableview.backgroundColor = .white
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "diylistcell") as! diylistcellTableViewCell
cell.diytitle.text = names[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let addbutton = UITableViewRowAction(style: .normal, title: "Add") { (rowAction, indexpath
) in
print("Add clicked")
let mycarvc = MyCarViewController()
mycarvc.diynames.append(contentsOf: self.hcdiynames)
let hcindexpath = IndexPath(row: mycarvc.diynames.count - 1, section: 0)
mycarvc.mycartableview.insertRows(at: [hcindexpath], with: .automatic) //this is where the error occurs. Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
mycarvc.mycartableview.endUpdates()
}
addbutton.backgroundColor = UIColor.darkGray
return [addbutton]
}
Clear Image of Error
That's where my pain is coming from. As you could see in the picture above the highlighted area it says that my array coming from the main vc is a count of 8. That checks out completely because the original array has 3 and I am appending 5 new ones. The error implicitly found nil has left me clueless in this scenario. If anybody has any suggestions on how to fix this problem it would be highly appreciated, thank you .
This is a common error when you try to transfer data between VC , I usually create 1 variable which will store what I want and after in the viewDidLoad() I give the value of this variable to what I really want , IN your code the equivalent is
class MainVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet var mycartableview: UITableView!
var passedcar = String()
// I JUST CREATED THE VARIABLE WHICH WILL HOLD OUR VALUES
var diynamesContainer = [String]()
///////////////////
var diynames: [String] = ["a","b","c"]
override func viewDidLoad() {
super.viewDidLoad()
mycartableview.tableFooterView = UIView(frame: CGRect.zero)
// I ADD TO OUR ARRAY THE VALUE OF THE diynamesContainer
diynames.append(contentsOf: diynamesContainer)
//////////////////
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return diynames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let diyname = diynames[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "mycarcell") as! mycarcell
cell.mycartitle.text = diyname
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
diynames.remove(at: indexPath.row)
tableView.beginUpdates()
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
}
}
/*
// MARK: - Navigation
and in our main vc you replace
let mycarvc = MyCarViewController()
mycarvc.diynames.append(contentsOf: self.hcdiynames)
by
let mycarvc = MyCarViewController()
mycarvc.diynamesContainer = self.hcdiynames
Try to run your code, the error will go away

Table View is not reflecting change in size

//
// ViewController.swift
// practise
//
// Created by ali on 29/11/2019.
// Copyright © 2019 smartsolution. All rights reserved.
//
import UIKit
class nestedviewcontroller: UIViewController {
var maindatacells:[String]=["m1","m2","m3","m9"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension nestedviewcontroller:UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
tableView.rowHeight = UITableView.automaticDimension
return maindatacells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! maintablecell
cell.lbltitle.text = maindatacells[indexPath.row]
cell.setdata(cont: self)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
var height = cell.frame.height
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
var heightjjj = cell.frame.height
}
}
class maintablecell:UITableViewCell,UITableViewDelegate,UITableViewDataSource{
#IBOutlet weak var tblheightconstraint:NSLayoutConstraint!
#IBOutlet weak var lbltitle:UILabel!
#IBOutlet weak var tblinside:UITableView!
var cellheight:CGFloat = 20
var parentcont:UIViewController!
override func awakeFromNib() {
super.awakeFromNib()
tblinside.delegate = self
tblinside.dataSource = self
}
func setdata(cont:UIViewController){
self.parentcont = cont
}
var datacells = ["i1","i2","i3","67"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datacells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = datacells[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == 0{
cellheight = 0
}
cellheight += cell.contentView.frame.height
if indexPath.row == datacells.count - 1{
// var tbl = self.superview as! UITableView
// tblinside.estimatedRowHeight = cellheight
// tbl.estimatedRowHeight = cellheight
tblheightconstraint.constant = cellheight
tblinside.beginUpdates()
tblinside.endUpdates()
self.setNeedsDisplay()
self.setNeedsLayout()
self.setNeedsUpdateConstraints()
self.parentcont.view.setNeedsLayout()
self.parentcont.view.setNeedsDisplay()
// var siz = self.frame.size
// //
// self.frame.size = CGSize(width: siz.width, height: siz.height + 30)
}
}
}
I am updating tableview size programmaticaly by changing its constraint. But tableview is not reflecting the change untill i refresh tableview by scrolling.I have tried many functions to update layout of main cell or tableview but i didnt find anything helping.
The tableview resize perfectly when i scroll the maintableview and the cell freshes