Repeating values in Stepper inside TableViewCell when scrolling - xcode

Stepper problem when cells need scroll.
My_TableViewCell.swift
import UIKit
class My_TableViewCell: UITableViewCell {
#IBOutlet weak var My_Label1: UILabel!
#IBOutlet weak var My_Label2: UILabel!
#IBOutlet weak var My_Stepper: UIStepper!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
...
My_TableViewController.swift
import UIKit
var My_Ids = ["C01","C02","C03","C04","C05","C06","C07","C08","C09","C10"]
var My_Values = ["0","0","0","0","0","0","0","0","0","0"]
class My_TableViewController: UITableViewController {
#IBAction func My_Stepper(sender: AnyObject) {
let point = sender.convertPoint(CGPointZero, toView: tableView)
let indexPath = self.tableView.indexPathForRowAtPoint(point)!
let cell = self.tableView.cellForRowAtIndexPath(indexPath) as! My_TableViewCell
cell.My_Label2.text = "\(Int(cell.My_Stepper.value))"
}
...
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return My_Ids.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell =
self.tableView.dequeueReusableCellWithIdentifier(
"My_TableCell", forIndexPath: indexPath)
as! My_TableViewCell
let row = indexPath.row
cell.My_Label1.text = My_Ids[row]
cell.My_Label2.text = "\(Int(cell.My_Stepper.value))"
return cell
}
...
When all cells fit in a "page" the Stepper works well but if the cells are resized and you need scroll the tableview the values are repeated in other cells.
If you alter the value on the cells C06 and C07 this will to reflect C01 and C02 cells and vice-versa.
Please view this image showing the snapshots with the errors

UITableViewController intentionally reuses cells as an optimization. You need to clear the old cell settings as part of your solution. Add a prepareForReuse method to your My_TableViewCell class.
You do this:
- (void) prepareForReuse
{
[super prepareForReuse];
// clear previous cell settings
}
Additional Notes:
recommend against calling cellForRowAtIndexPath directly. See this thread.
recommend you use Pascal casing for class names: Use MyTableViewCell instead of My_TableViewCell.

Related

Prototype Cell width runs off the page in a Table View

Fairly new to coding and this is my first post here. I added a Prototype Cell to a Table View Cell but when I run the project the cell runs off the page (on the right)? Does anyone have any help they can provide?
This is the ViewController code:
import UIKit
class ConsultationsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
ConsultationFunctions.readConsultations(completion: { [weak self] in
self?.tableView.reloadData()
})
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Data.consultationModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! ConsutationsTableViewCell
cell.setup(consultationModel: Data.consultationModels[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
And this is the TableViewController code:
import UIKit
class ConsutationsTableViewCell: UITableViewCell {
#IBOutlet weak var cardView: UIView!
#IBOutlet weak var titleLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
cardView.layer.shadowOffset = CGSize.zero
cardView.layer.shadowColor = UIColor.systemBlue.cgColor
cardView.layer.cornerRadius = 10
}
func setup(consultationModel: ConsultationModel) {
titleLabel.text = consultationModel.title
}
}
I've tried adjusting the Storyboards Identity, Attributes and Size Inspectors as best I can but just don't understand where I've gone wrong? Any guidance is greatly appreciated
I don't see the interface constraints in your code, so I guess you have them in the Storyboard, or ar least you should.
I suggest you to go through some tutorials or guides to "Add New Constraints" for cardView and titleLabel. Here you have a simple one:
https://www.ralfebert.de/ios-examples/uikit/uitableviewcontroller/custom-cells/

Why the cell height is not changing on tapping the button once. It is working only when I tap the button twice

Click Here To see the UI of my app
Here In the image you can see the ui.
--> There is a tableView & a button on the main view.
--> I have taken a custom tableViewCell class
In the cell I have taken a UIView
Constraints Added To That View are:
centre horizontally, height, width, top & bottom constraint
I have added a outlet of the height constraint to the TVCell class
--> I have taken a button and added a event handler to it
--> Button Event handler:
In button event handler I am just changing the height of the view in the first cell and reloading the cell.
Now the problem is that height of the cell is changing when I tap on the button. But its happening only when I tap one the button twice. So I want to know why is it happening. Here I am adding my code below.
I have one solution for this problem which you can see after you see after the code of the ViewController & TableViewCell Class
VIEW CONTROLLER CLASS
import UIKit
class ViewController: UIViewController,UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.separatorColor = UIColor.black
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
return cell
}
#IBAction func buttonAction(_ sender: Any) {
let indexPath = IndexPath(row: 0, section: 0)
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
if cell.viewHeightConstraint.constant == 75 {
cell.viewHeightConstraint.constant = 10
}
else{
cell.viewHeightConstraint.constant = 75
}
tableView.reloadRows(at: [indexPath] , with: UITableView.RowAnimation.automatic)
}
}
TABLEVIEWCELL CLASS
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var viewHeightConstraint: NSLayoutConstraint!
override func awakeFromNib() {
super.awakeFromNib()
//Setting View Height To 75
viewHeightConstraint.constant = 75
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
You can get this source code from this link below
https://github.com/himansudev/tableViewIssue_15_4_20_1.git
Now I have a solution for this problem but I believe its not a proper solution. So what I have done is as shown below
1) I have modified the button event handler, see below is the modified code. Please refer to the above code to identify the changes that I have made to this event handler
#IBAction func buttonAction(_ sender: Any) {
let indexPath = IndexPath(row: 0, section: 0)
tableView.reloadRows(at: [indexPath] , with: UITableView.RowAnimation.automatic)
}
2) Secondly I have added this extra piece of code , see below
override func viewDidLayoutSubviews() {
print("viewDidLayoutSubviews")
let indexPath = IndexPath(row: 0, section: 0)
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
if cell.viewHeightConstraint.constant == 75 {
cell.viewHeightConstraint.constant = 10
}
else{
cell.viewHeightConstraint.constant = 75
}
}
Find the source code after changes below
https://github.com/himansudev/tableViewSolution_15_4_20_1.git
Now after doing these two changes it is working (but sometimes it doesn't work when I tap on the button rapidly many times) but the problem is the viewDidLayoutSubviews() is not getting called but when I comment it than the cell is not working as expected .
SO I want to know why is it behaving that way???
First of all you need to add also the UITableViewDelegate to your ViewController and a var like this:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var cellHeight: CGFloat = 75
and the heightForRow function which will return the right Height:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeight
}
Then on your button action:
#IBAction func buttonAction(_ sender: Any) {
if cellHeight == 75 {
cellHeight = 10
}
else{
cellHeight = 75
}
tableView.reloadData()
}
Also remove the constraint viewHeightConstraint because you do not need it.

UIImageView in table cell is not staying within frame original frame?

So this is what is happening:
I've added a red background color to the image view so you can see how much it's going over.
I've tried tableView(:willDisplayHeaderView:), I've tried checking off Subviews, I've tried AspectFit, AspectFill, & ScaletoFill But the UIImageView's keep going beyond their original boundaries and I don't understand why.
Here's some code from my UITableViewController:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("scheduleCell", forIndexPath: indexPath) as! ScheduleTableViewCell
let eventList = schedule?.schedule[dayOfWeek[indexPath.section]]!
let event = eventList![indexPath.row]
cell.labelEvent.text = event.act.rawValue
cell.labelTime.text = "\(event.getTime(event.start)) - \(event.getTime(event.end))"
return cell
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let tableViewCell = cell as! ScheduleTableViewCell
let eventList = schedule?.schedule[dayOfWeek[indexPath.section]]!
let event = eventList![indexPath.row]
tableViewCell.imageView?.image = UIImage(named: "\(schedule!.potato.mode)-\(event.act.rawValue)")
tableViewCell.imageView?.backgroundColor = UIColor.redColor()
tableViewCell.imageView?.contentMode = .ScaleAspectFit
}
And this is my custom cell class:
class ScheduleTableViewCell: UITableViewCell {
#IBOutlet weak var imageEvent: UIImageView!
#IBOutlet weak var labelEvent: UILabel!
#IBOutlet weak var labelTime: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
First, setting the imageView's clipsToBounds property to true will prevent the image from spilling over the bounds of the imageView.
Second, the image is clearly bigger than the imageView, so I think the imageView is not spilling over, the image inside it is spilling over. So, you will either need to resize the image or use Scale*Fill modes to show the full image or crop it as appropriate.
HTH.

How to transfer data from table cell to a new view controller using prepare for segue method?

How to use prepare for segue to transfer the images (tweetImg) and date (dateLbl) from tablecell (mainCell) to the Newviewcontroller when I select the cell? in my case I am using parse.com as my backend to retrieve the images and dates data. I am new to programming would appreciate some help, thank you.
mainVC
import UIKit
class mainVC: UIViewController, UITableViewDataSource, UITableViewDelegate, {
#IBOutlet weak var resultsTable: UITableView!
var resultsStartdateArray = [String]()
var resultsTweetImageFiles = [PFFile?]()
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsTweetImageFiles.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 350
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:mainCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! mainCell
cell.dateLbl.text = self.resultsStartdateArray[indexPath.row]
resultsTweetImageFiles[indexPath.row]?.getDataInBackgroundWithBlock({
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.tweetImg.image = image
}
})
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("SendDataSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SendDataSegue")
{
let destination: NewViewController = segue.destinationViewController as! NewViewController
// I believe the missing code should be here
}
}
}
mainCell
import UIKit
class mainCell: UITableViewCell {
#IBOutlet weak var tweetImg: UIImageView!
#IBOutlet weak var dateLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
NewViewController
import UIKit
class NewViewController: UIViewController {
#IBOutlet weak var dateLbl: UILabel!
#IBOutlet weak var tweetImg: UIImageView!
var titleString: String!
override func viewDidLoad()
{
super.viewDidLoad()
self.dateLbl.text = self.titleString
}
Bellow i have mentioned a sample template code. organize your code according to bellow mentioned code. important part is select a cell in the prepareForSegue instead of in didSelectRowAtIndexPath. Which is let IndexPath = self.tableView.indexPathForSelectedRow()!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Index path is the selected cell
let IndexPath = self.tableView.indexPathForSelectedRow()!
//Here you can assign your tweetImg and dateLbl
let newViewController = segue.destinationViewController as! NewViewController
newViewController.dateLbl.text = //your date label value
//here assign your image to destination view controller property
}
Delete the method didSelectRowAtIndexPath and connect the segue to the table view cell rather than the view controller.
When a cell is selected it's passed as the sender parameter in the prepareForSegue method.
A side note : Don't perform background tasks in the view – the cellForRowAtIndexPath method – , do it in the model – the items in the data source array – and then call reloadData()

Xcode 7 - Cell content not displayed into an empty label

I'm trying to display a cell content into an empty UILabel, but after I upgraded to Xcode 7, the content didn't show up. I was following the same mechanism and it worked on Xcode 6, but since I'm new to Swift I may have something wrong in the code.
TableViewController:
import UIKit
class TableViewController: UITableViewController {
struct dataModel {
var name:String
var val:Double
}
let foods = [dataModel(name: "name1", val: 3.3),
dataModel(name: "name2", val: 5.5)]
#IBOutlet var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(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 foods.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
// Configure the cell...
let foodCell = foods[indexPath.row]
cell.textLabel?.text = foodCell.name
return cell
}
var valueToPass:String!
var valueInt:Int!
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let indexPath = tableView.indexPathForSelectedRow;
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel!.text
performSegueWithIdentifier("showCalc", sender: self)
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showCalc") {
let viewController = segue.destinationViewController as! calcViewController
viewController.passedValue = valueToPass
}
}
}
ViewController where I want to display the tapped cell into an empty label:
import UIKit
class calcViewController: UIViewController {
#IBOutlet var text: UILabel!
#IBOutlet var empty1: UILabel!
var passedValue:String!
override func viewWillAppear(animated: Bool) {
empty1.text = passedValue
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
As a result, there is no error, but there is nothing displayed inside the empty label.
The other thing I want to achieve is to display the Int value into another label and then do some calculations, but this would be another question. Thanks in advance!
There are several issues in this code. First you are obviously missing some closing braces. But I assume this is a copy-paste error.
Why do you use didDeselectRowAtIndexPath? Don't you have a segue from the table view cell to the next controller? Then you should get the text label in prepareForSegue by using tableView.indexPathForSelectedRow.
If you like to keep it this way you should use didSelect... in stead of didDeselect....
You should take the value you want to pass to the next view controller direct from the data and not from the cell. You have the data you present in the table in the foods array.
Class names should always start with a capital letter. ALWAYS!
Having the data model within the controller is poor design. You should have the struct separated in its own file. In this case you could even hand the complete data object to the next view controller.

Resources