Create a custom list on Storyboard Xcode - xcode

Being a beginner with Xcode, I wanted to know if it was possible to create a list with our own components? I explain, it would be to make a list of favorites scrolling on an Xcode view, with an image, a button to delete it, and a text. It is obvious that I will have to create more components but how to put them in a list without limits?
The prototype design is as follows:
Here !
Thank you in advance, Sincerely.

Yes you can make your own list cells. For that you will need to,
create your own UITableViewCell and add your componenents (2x UIImageViews, 1x UILabel)
register your cell to the UITableView you want to display the cell in with the identifier
Conform to both UITableViewDelegate & UITableViewDataSource
Refer this blog to learn more as I barely scratched the surface with the explanation
You can add data to the table as follows
/// Conforming to the UITableViewDelegate, UITableViewDataSource protocols
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// Table view to display data
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// setting the datasource and delegate
tableview.delegate = self
tableview.dataSource = self
}
/// 2d Array to store data
let data = [["Melon", "Glace"], ["Epinard"], ["one", "two", "three"] ]
func numberOfSections(in tableView: UITableView) -> Int {
return self.data.count
}
/// UITableViewDataSource protocol stubs
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.data[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as? CustomTableViewCell {
cell.name = data[indexPath.section][indexPath.row]
return cell
}
return UITableViewCell()
}
}

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/

swift 3 change uitableviewcell after click uitableviewcell from another view controller?

I am trying to make my tableview cell from viewcontroller 1 change when the user click on a cell from tableview cell from viewcontroller 2. I know that I have to work with the function
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
however, I am not sure how I would accomplish what I wanted.
Here's my code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = changeHotelTableView.indexPathForSelectedRow;
let currentCell = changeHotelTableView.cellForRow(at: indexPath!) as! ChangeHotelTableViewCell
var valueToPass = currentCell.textLabel?.text
}
I want to get the valueToPass variable into my cell at another' view controller; say this is called timeViewController with timeTableView and a timeTableViewCell. How will I do this?
Thanks for your help and time in advance
Perhaps you should try with Protocol.
ViewController2:
protocol UserPressTheCell: NSObjectProtocol
{
func didUserPressTheCellWith(indexPath: IndexPath, text: String)
}
class ViewController2: UIViewController
{
//declare delegate
weak var delegate: UserPressTheCell?
....
func tableview(_ tableview: UITableView, didSelectRowAt indexPath: IndexPath)
{
let indexPath = changeHotelTableView.indexPathForSelectedRow;
let currentCell = changeHotelTableView.cellForRow(at: indexPath!) as! ChangeHotelTableViewCell
self.delegate?.didUserPressTheCellWith(indexPath: indexPath, text: currentCell.textLabel?.text)
}
}
Then implement in ViewController1:
class ViewController1: UIViewController, UserPressTheCell
{
#IBOutlet weak var tableview: UITableView!
...
//MARK: UserPressTheCell
func didUserPressTheCellWith(indexPath: IndexPath, text: String)
{
let cell = self.tableView.cellForRow(at: indexPath!) as! "Your VC1's cell"
cell.textLabel?.text = text
}
}
To be sure delegate will not be nil:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
let vc2 = segue.destination as! ViewController2
vc2.delegate = self
}
or wherever you segue to ViewController2.
Maybe this is the best way to accomplish what you wanted.

When trying to display images from an array on a table view, I am receiving an the error "exc_bad_instruction (code=EXC_I386_INVOP, subcode=0x0"

To create an "Events" page of an app, I am using table view to list an image, name, and details of the event. You will be able to select an event, as well as add one.
I am currently populating my table with data stored as an array, however when I try to place the images data, I return an error in this line of code:
cell.photo.image = images[indexPath.row]
Can anyone help figure out why I am returning this error?
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
var names = ["BTown Diner", "Dunnkirk", "Chocolate Mousse", "Lil Wayne", "Annie", "Campus Squad Social"]
var details = ["Free drink with meal after 12 AM", "LADIES drink free", "10% off all ice cream!", "Lil 500 concert", "an IU Theater Production", "Bring your Squad to the Campus Squad Social"]
var images = [UIImage(named: "btown_diner"), UIImage(named: "dunnkirk"), UIImage(named: "choco_moose"), UIImage(named: "lilwayne"), UIImage(named: " ")]
override func viewDidLoad() {
super.viewDidLoad()
// 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, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
cell.name.text = names[indexPath.row]
cell.detail.text = details[indexPath.row]
cell.photo.image = images[indexPath.row]
return cell
}
}
Additionally, here is my CustomCell.swift file
import UIKit
class CustomCell: UITableViewCell {
#IBOutlet var photo: UIImageView!
#IBOutlet var name: UILabel!
#IBOutlet var detail: 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
}
}
Your variable names has a count of 6.
Your table will have 6 rows from return names.count. However, your variable images has a count of 5.
I think when your function tableView:cellForRowAtIndexPath gets called with indexPath equal to 5, your images array is out of bounds.

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.

Repeating values in Stepper inside TableViewCell when scrolling

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.

Resources