UITableView keeps autoscrolling to top - ios

When the user tries scrolling down the table (goes past the keyboard height), it automatically scrolls back to the top of table, leaving the user unable to press any of the keys in the bottoms rows of the table. How do I disable this autoscroll to top? Note this is different from the scrollsToTop property.
import UIKit
class KeyboardViewController: UIInputViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView = UITableView()
let screenSize: CGRect = UIScreen.mainScreen().bounds
let buttonTitles = [
"XX",
"YY"
]
override func viewDidLoad() {
super.viewDidLoad()
let screenWidth = screenSize.width
let screenHeight = screenSize.height
tableView.frame = CGRectMake(0,0,screenWidth,screenHeight - 40)
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self,forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.buttonTitles.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
cell.textLabel?.text = self.buttonTitles[indexPath.row]
cell.textLabel?.textAlignment = .Center
cell.textLabel?.font = UIFont(name: "Helvetica Neue", size: 14)
cell.textLabel?.textColor = UIColor.whiteColor()
cell.textLabel?.numberOfLines = 0
cell.backgroundColor = UIColor(red: 176/255, green: 15/255, blue: 15/255, alpha: 1.0)
cell.preservesSuperviewLayoutMargins = false
cell.layoutMargins = UIEdgeInsetsZero
cell.separatorInset = UIEdgeInsetsZero
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var string = buttonTitles[indexPath.row]
(textDocumentProxy as! UIKeyInput).insertText("\(string)")
}

Move your code except
tableView.delegate = self
tableView.dataSource = self
to viewWillAppear

Related

Why isn’t my custom UITableView cell showing?

I’ve implemented a custom cell for a UITableView, but when I run the Playground it’s just a standard table. It’s probably something stupid simple, but I’m very new to UIKit and somewhat new to Swift.
Also, I’ve tried to implement a “sticky header”, but no matter what I try the header scrolls with the rest of the table.
import UIKit
import PlaygroundSupport
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 19
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CardCell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
cell.messageLabel.text = "yo"
return cell
}
var convoTableView = UITableView()
override func viewDidLoad(){
super.viewDidLoad()
convoTableView = UITableView(frame: self.view.bounds, style:
UITableView.Style.plain)
convoTableView.backgroundColor = UIColor.white
convoTableView.register(CardCell.self, forCellReuseIdentifier: "CardCell")
let header = UIView(frame: CGRect(x: 0, y: 0, width: convoTableView.frame.width, height: 100))
header.backgroundColor = .red
self.convoTableView.delegate = self
self.convoTableView.dataSource = self
let yourLabel = UILabel(frame: CGRect(x: 10, y: 0, width: 100, height: 100))
yourLabel.textColor = UIColor.black
yourLabel.backgroundColor = UIColor.white
yourLabel.text = "mylabel text"
header.addSubview(yourLabel)
convoTableView.tableHeaderView = header
convoTableView.estimatedSectionHeaderHeight = 40.0
self.view.addSubview(convoTableView)
}
}
class CardCell: UITableViewCell {
let messageLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let dateLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 8)
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let containerView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
containerView.addSubview(messageLabel)
containerView.addSubview(dateLabel)
self.contentView.addSubview(containerView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
PlaygroundPage.current.liveView = ViewController()
Here's all the code you need here to make a custom cell and sticky header:
import UIKit
import PlaygroundSupport
class ViewController: UITableViewController {
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .purple
return view
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
50
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
19
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func viewDidLoad(){
super.viewDidLoad()
tableView.register(CardCell.self, forCellReuseIdentifier: "CardCell")
}
}
class CardCell: UITableViewCell { }
PlaygroundPage.current.liveView = ViewController()
To make the header sticky and non-scrollable with the table view you need to take a different UIView above the table view and give the frames of the table just below the UiView.
customView = MyCustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
self.view.addSubview(customView

One UITableViewCell is controlling others

Does anyone know what's happening here? I've configured a UITableView with CollectionViewCells, and each of these cells is supposed to operate independently of each other, yet when I swipe one it controls another cell which is 3 cells underneath it.
Tried to reconfigure my UITableViewCells and the CollectionViewCells. But I'm not exactly sure what to do
//TableView controler
import UIKit
import CardsLayout
import CHIPageControl
class eventsFeed: UIViewController, UITableViewDelegate, UITableViewDataSource{
// Global Variable
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
tableView = UITableView(frame: CGRect(x: self.view.bounds.minX, y: self.view.bounds.minY+UIApplication.shared.statusBarFrame.height, width: self.view.bounds.width, height: self.view.bounds.height))
tableView.delegate = self
tableView.separatorStyle = .none
tableView.dataSource = self
tableView.showsVerticalScrollIndicator = false
self.view.addSubview(tableView)
tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.backgroundColor = UIColor.white
cell.selectionStyle = .none
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 430.0;//Choose your custom row height
}
}
//CollectionViewCell for TableView
import UIKit
import CardsLayout
class TableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
var collectionView: UICollectionView!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
collectionView = UICollectionView(frame: CGRect(x: 0, y:0, width: UIScreen.main.bounds.width, height: 410.0), collectionViewLayout: layout)
collectionView.center = CGPoint(x: 187.5, y: 180)
collectionView.collectionViewLayout = CardsCollectionViewLayout()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
collectionView.backgroundColor = UIColor.white
self.addSubview(collectionView)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
var colors: [UIColor] = [
UIColor(red: 237, green: 37, blue: 78),
UIColor(red: 249, green: 220, blue: 92),
UIColor.blue,
UIColor(red: 1, green: 25, blue: 54),
UIColor(red: 255, green: 184, blue: 209),
UIColor(red: 237, green: 37, blue: 78),
UIColor(red: 249, green: 220, blue: 92)
]
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
cell.layer.cornerRadius = 12.0
cell.backgroundColor = colors[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colors.count
}
}
Video of issue: https://www.reddit.com/r/iOSProgramming/comments/btcok4/does_anyone_know_whats_happening_here_ive/
Cells are reused. That means that you have to choose different strategy of working with them.
Save somewhere current state for each table view cell (for example in structs in an array) and then configure cell based on this state in cellForRowAt delegate's method.

Add UIView and UITableView programmatically

I am trying to make this, as in the first picture:
Image 1
Image 2
But the view somehow does not show up like I want it to. Here you can see my full project code:
import UIKit
import RealmSwift
import CVCalendar
class Test: UIViewController, UITableViewDelegate, UITableViewDataSource {
var myTableView: UITableView = UITableView()
var itemsToLoad: [String] = ["One", "Two", "Three"]
var myView = UIView()
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 4/255, green: 4/255, blue: 4/255, alpha: 1.0)
self.navigationController?.navigationBar.barStyle = .black
self.navigationController?.navigationBar.tintColor = UIColor.white
self.navigationItem.title = "Test"
self.navigationController?.navigationBar.prefersLargeTitles = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Get main screen bounds
let screenSize: CGRect = UIScreen.main.bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
myView.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 150)
myView.backgroundColor = .black
self.view.addSubview(myView)
myTableView.frame = CGRect(x: 0, y: 50, width: screenWidth, height: screenHeight-50);
myTableView.dataSource = self
myTableView.delegate = self
myTableView.backgroundColor = .blue
myTableView.layer.borderWidth = 3
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(myTableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return itemsToLoad.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = self.itemsToLoad[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("User selected table row \(indexPath.row) and item \(itemsToLoad[indexPath.row])")
}
}
Why won't it show up? The first picture is how I want it, then second picture is how it looks now.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if self.itemsToLoad[indexPath.row] != nil {
cell.textLabel?.text = self.itemsToLoad[indexPath.row]
cell.backgroundColor = .white
}else {
cell.backgroundColor = .blue
}
return cell
}

UITableView.automaticDimension Not working tableView detailTextLabel

I am implementing UITableViewController Programmatically (No Storyboards!).
I tried many possible ways to implement automatic resizing of TableViewCell's detailTextLabel but none is working. I don't know what I am missing or whether it's a bug! Here's what I tried:
//Class - tableViewContoller
override func viewDidLoad() {
super.viewDidLoad()
setUpTableView()
}
func setUpTableView() {
tableView.tableFooterView = UIView(frame: CGRect.zero)
tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)
tableView.contentInset = UIEdgeInsets(top: 10.0, left: 0.0, bottom: 10.0, right: 0.0)
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension //Tried 44 -> Not working either
tableView.reloadData()
}
//cellForRowAt IndexPath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: UITableViewCell.CellStyle.value1, reuseIdentifier: cellId)
}
cell?.detailTextLabel?.numberOfLines = 0
cell?.detailTextLabel?.lineBreakMode = .byWordWrapping
cell?.selectionStyle = .none
switch indexPath.row {
case 0:
cell?.textLabel?.text = "Case 1"
cell?.detailTextLabel?.text = caseDetails?.details
case 1:
cell?.textLabel?.text = "Case 2"
cell?.detailTextLabel?.text = caseDetails?.bio
default:break
}
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
I have 2-3 cells where detailTextLabel may have multiple lines.
Please let me know what's that I'm missing here. What I figured after reading on the Internet is to add custom constraints, but I don't think that'll work either.
You have to add constraints for that cell?.detailTextLabel
cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: cellId)
}
cell?.detailTextLabel?.numberOfLines = 0
cell?.detailTextLabel?.lineBreakMode = .byWordWrapping
cell?.selectionStyle = .none
cell?.detailTextLabel?.layer.backgroundColor = UIColor.yellow.cgColor
// ALLOW MANUAL CONSTRAINTS
cell?.detailTextLabel?.translatesAutoresizingMaskIntoConstraints = false
// TOP +15, BOTTOM -15, RIGHT -15
cell?.detailTextLabel?.topAnchor.constraint(equalTo: (cell?.contentView.topAnchor)!, constant: 15).isActive = true
cell?.detailTextLabel?.bottomAnchor.constraint(equalTo: (cell?.contentView.bottomAnchor)!, constant: -15).isActive = true
cell?.detailTextLabel?.rightAnchor.constraint(equalTo: (cell?.contentView.rightAnchor)!, constant: -10).isActive = true
switch indexPath.row {
case 0:
cell?.textLabel?.text = "Case 1"
cell?.detailTextLabel?.text = "hi\nhello\nwelcome\nhow are you"
case 1:
cell?.textLabel?.text = "Case 2"
cell?.detailTextLabel?.text = "caseDetails?.bio\n\n\n123456"
default:break
}
return cell!
}
Output
Should work if you set your estimated row height to an actual value. You can't have both set to .automaticDimension.

TableView background keeps white

I'm having a problem with my parallax effect. I'm having a tableView and a ImageView above the tableView. Now when the user scrolls from the top I want to stretch the image a bit. But the problem is that my tableView keeps having a white background like you can see on the screenshot. So the image isn't visible. The screenshot is taken when the viewcontroller loads and then I just pull down as far as I can go. The tableView has backgroundColor .clear so I don't why it isn't working.
My code:
import UIKit
import PureLayout
class ViewController: UIViewController {
lazy var headerImageView: UIImageView = {
let imageView = UIImageView(forAutoLayout: ())
imageView.image = UIImage(named: "test")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
lazy var tableView: UITableView = {
let tableView = UITableView(forAutoLayout: ())
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.isOpaque = false
tableView.backgroundColor = .clear
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "default")
tableView.tableFooterView = UIView()
tableView.showsVerticalScrollIndicator = false
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.headerImageView)
self.headerImageView.autoPinEdge(toSuperviewEdge: .left)
self.headerImageView.autoPinEdge(toSuperviewEdge: .right)
self.headerImageView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
self.headerImageView.autoSetDimension(.height, toSize: 100)
self.view.addSubview(self.tableView)
self.tableView.autoPinEdge(toSuperviewEdge: .left)
self.tableView.autoPinEdge(toSuperviewEdge: .right)
self.tableView.autoPinEdge(toSuperviewEdge: .bottom)
self.tableView.autoPinEdge(.top, to: .bottom, of: self.headerImageView)
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "default", for: indexPath)
cell.textLabel?.text = "test"
cell.backgroundColor = .red
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Parallax functionality
let yOffset = scrollView.contentOffset.y * 0.2
let availableOffset = min(yOffset, 60)
let contentRectYOffset = availableOffset / self.headerImageView.frame.size.height
self.headerImageView.layer.contentsRect = CGRect(x: 0.0, y: contentRectYOffset, width: 1, height: 1)
}
}

Resources