Use two different custom UITableView Cells - ios

I want to have multiple cells with each having a label in it.
But as a last cell, I want to have a button instead of the label, which should navigate back to my main viewcontroller.
The labels are working, but I can't make a cell with a button in it running. Here's my Code for the UITableViewController:
class StatsViewController: UITableViewController {
var vc = ViewController()
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let cell2 = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
if let label = cell.viewWithTag(1000)as? UILabel{
if indexPath.row == 0 {
label.text = "Row 0"
}
else if indexPath.row == 1{
label.text = "Row 1"
}
else if indexPath.row == 2{
label.text = "Row 2"
}
else if indexPath.row == 3{
label.text = "Row 3"
}
return cell
}
if let button = cell2.viewWithTag(1001) as? UIButton {
if indexPath.row == 4{
return cell2
}
}
return UITableViewCell()
}
}
I idenified the label-cell in the storyboard with "cell" and the button-cell with "cell2".
Then I tagged the label with value "1000" and the button in cell2 has Tag = 1001
(WEITER is the Button)
Edited my code thanks to #Sh_Khan and # like this. Now, it does show me the button BUT not the labels..
class StatsViewController: UITableViewController {
var vc = ViewController()
override func viewDidLoad() {
super.viewDidLoad()
// tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
// tableView.reloadData()
//tableView.delegate = self
}
let timestamp = DateFormatter.localizedString(from: NSDate() as Date, dateStyle: .medium, timeStyle: .short)
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellId = (indexPath.row == 4) ? "cell2" : "cell"
if let label = cell.viewWithTag(1000)as? UILabel{
if indexPath.row == 0 {
label.text = "Row 0"
}
else if indexPath.row == 1{
label.text = "Row 1"
}
else if indexPath.row == 2{
label.text = "Row 2"
}
else if indexPath.row == 3{
label.text = "Row 3"
}
return tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
}
if let button = cell2.viewWithTag(1001) as? UIButton {
if indexPath.row == 4{
return tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
}
}
return UITableViewCell()
}
}

In your current code this
if let button = cell2.viewWithTag(1001) as? UIButton {
will never hit as the return here
return cell
will always run , You need
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexpath.row == 19) { // last row as you have 20
let cell2 = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
return cell
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if let label = cell.viewWithTag(1000)as? UILabel{
if indexPath.row == 0 {
label.text = "Row 0"
}
else if indexPath.row == 1{
label.text = "Row 1"
}
else if indexPath.row == 2{
label.text = "Row 2"
}
else if indexPath.row == 3{
label.text = "Row 3"
}
return cell
}
return cell
}
}
Tip: instead of using tags create outlets

Related

How to manage with custom SegmentControllCell to tableview cell?

I tried to manage from custom segment control cell into ViewController's tableview cell.
This is My custom segment control class:
protocol SegmentControllerCellDelegate: AnyObject {
func manageSegmentControl(cell: SegmentControllerCell)}
class SegmentControllerCell: UITableViewCell, ReusableView, NibLoadableView {
#IBOutlet weak var segmentController: UISegmentedControl!
weak var delegate: SegmentControllerCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
setupUI()
}
#IBAction func tappedSegmentControll(_ sender: UISegmentedControl) {
self.delegate?.manageSegmentControl(cell: self )
}}
And this is my view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch BrandSection(rawValue: indexPath.section)! {
case .profile:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandTableViewCell.self), for: indexPath) as? BrandTableViewCell else { return UITableViewCell() }
cell.cellType = .brandPage
return cell
case .segment:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SegmentControllerCell.self), for: indexPath) as? SegmentControllerCell else { return UITableViewCell() }
cell.delegate = self
return cell
case .products:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandProductionsCell.self), for: indexPath) as? BrandProductionsCell else { return UITableViewCell() }
return cell
}
}
extension BrandProfileVC: SegmentControllerCellDelegate {
func manageSegmentControl(cell: SegmentControllerCell) {
if cell.segmentController.selectedSegmentIndex == 0 {
self.brandTableView.reloadData()
print("index 0")
} else if cell.segmentController.selectedSegmentIndex == 1 {
self.brandTableView.reloadData()
print("index 1")
}
}}
I just want to show when I clicked segment control tab, different cell under the segment control.
Please try to set the cell.tag as indexPath.row from cellForRow and then try to print the cell.tag inside the manageSegmentControl in your ViewController
This is the Code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch BrandSection(rawValue: indexPath.section)! {
case .profile:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandTableViewCell.self), for: indexPath) as? BrandTableViewCell else { return UITableViewCell() }
cell.cellType = .brandPage
cell.tag = indexPath.row
return cell
case .segment:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SegmentControllerCell.self), for: indexPath) as? SegmentControllerCell else { return UITableViewCell() }
cell.delegate = self
cell.tag = indexPath.row
return cell
case .products:
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: BrandProductionsCell.self), for: indexPath) as? BrandProductionsCell else { return UITableViewCell() }
cell.tag = indexPath.row
return cell
}
}
extension BrandProfileVC: SegmentControllerCellDelegate {
func manageSegmentControl(cell: SegmentControllerCell) {
if cell.segmentController.selectedSegmentIndex == 0 {
self.brandTableView.reloadData()
print(cell.tag)
} else if cell.segmentController.selectedSegmentIndex == 1 {
self.brandTableView.reloadData()
print(cell.tag)
}
}
}

CellForItemAt: index path not updating variable

I am working with a UITableView that has a cell with a UISwitch in it. I have four tableViewCells, each from this same prototype cell. However, when I toggle the switch, the only way that the variables in the TableView CellForItemAt: section is when I pull the tableView so that it goes out of the screen, and the Reusable Cells are Reloaded. How can I make these variables refresh when the switches are toggled?
Here is my code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "onOffCell", for: indexPath) as! SettingsCellTableViewCell
if indexPath.section == 0 {
cell.textLabel?.text = OLLItems![indexPath.row]._text
if indexPath.row == 0 {
GlobalData.AllGlobalData.OLLImageState = cell.state //GlobalData.AllGlobalData.OLLImageState is an struct in another file
print("OLLImageState \(GlobalData.AllGlobalData.OLLImageState)")
}
if indexPath.row == 1 {
GlobalData.AllGlobalData.OLLAlgState = cell.state
print("OLLAlgState \(GlobalData.AllGlobalData.OLLAlgState)")
}
}
if indexPath.section == 1 {
cell.textLabel?.text = PLLItems![indexPath.row]._text
if indexPath.row == 0 {
GlobalData.AllGlobalData.PLLImageState = cell.state
print("PLLImageState \(GlobalData.AllGlobalData.PLLImageState)")
}
if indexPath.row == 1 {
GlobalData.AllGlobalData.PLLAlgState = cell.state
print("PLLAlgState \(GlobalData.AllGlobalData.PLLAlgState)")
}
}
return cell
}
Try doing it this way
Below code works properly in my repo but I changed it a bit to justify your scenario
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "switchCell", for: indexPath) as! SwitchContainingTableViewCell
cell.mySwitch.addTarget(self, action: #selector(switchChanged(_:)), for: .valueChanged)
return cell
}
func switchChanged(_ mySwitch: UISwitch) {
guard let cell = mySwitch.superview?.superview as? SwitchContainingTableViewCell else {
return // or fatalError() or whatever
}
self.value = mySwitch.isOn //define var value in your controller or do it locally
let indexPath = itemTable.indexPath(for: cell)
if indexPath.section == 0 {
if indexPath.row == 0 {
GlobalData.AllGlobalData.OLLImageState = self.value
}
}
}
I have added a target of the switch and in the target I'm getting the changed state of the switch. The same can be done within the cellForItemAt: by using state = mySwitch.isOn
Hope this helps!

Predictive tableView swift 4

I have 2 tableView with 2 tableView first to display data & sec for predictive texts and I'm using textField as searchBar so when I set the cell for the sec tableView is give me that error when I try to return the cell at cellForRowAt method
Cannot convert return expression of type UITableViewCell.Type to return type UITableViewCell
and that's my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCell", for: indexPath) as! searchCell
//cell.pics = receiveData[indexPath.item]
cell.titleCell.text = receiveData[indexPath.row].adeTitle
cell.cityCell.text = receiveData[indexPath.row].city
cell.dateCell.text = receiveData[indexPath.row].date
cell.distanceCell.text = receiveData[indexPath.row].distance
cell.priceCell.text = receiveData[indexPath.row].adePrice
if receiveData[indexPath.row].typ == "2" {
cell.kindCell.text = "used"
cell.kindCell.backgroundColor = UIColor.darkGray
cell.kindCell.textColor = UIColor.white
} else if receiveData[indexPath.row].typ == "1" {
cell.kindCell.text = "New"
} else {
cell.kindCell.text = "none"
cell.kindCell.backgroundColor = UIColor.darkGray
cell.kindCell.textColor = UIColor.white
}
} else {
var cell = searchTableView.dequeueReusableCell(withIdentifier: "Cell" )
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
}
cell?.textLabel?.text = inputs[indexPath.row]
}
return UITableViewCell
}
Looks like UITableViewCell's instance is not returned in your cellForRowAt method,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCell", for: indexPath) as! searchCell
...
// do your stuffs with cell
...
return cell
}
return UITableViewCell()
}

Use different type of cells and different number of rows in UITableViewController

I am trying to use a UITableViewController(Static table view) with 4 sections and each has a different type of cell.
The number of cells in a section depends on the data received from the web service. In the storyboard, I have created one type of cell in each section.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Number of rows in attachment sect
if section == 2 {
guard let currentDataModel = dataModel else { return 0 }
return currentDataModel.attachments.count
}
else if section == 3 {
guard let currentDataModel = dataModel else { return 0 }
return currentDataModel.contacts.count
}
return super.tableView(tableView, numberOfRowsInSection: section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let currentSection = indexPath.section
if currentSection == 2 {
let currentRow = indexPath.row
let cell = tableView.dequeueReusableCell(withIdentifier: "attachmentCell", for: indexPath) as! AttachmentViewCell
cell.setDataForCell(dataModel: dataModel?.attachments[currentRow], indexPath: indexPath)
return cell
}
//Show cells for Contact Section
else if currentSection == 3 {
let currentRow = indexPath.row
let cell = tableView.dequeueReusableCell(withIdentifier: "contactCell", for: indexPath) as! ContactViewCell
cell.setDataForCell(dataModel: dataModel?.contacts[currentRow], indexPath: indexPath)
return cell
}
return super.tableView(tableView, cellForRowAt: indexPath)
}
I am getting this error while calling dequeueReusableCellWithIdentifier:forIndexPath:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
Can I Use the different type of cells and a different number of rows in each section in a UITableViewController?
Can you try this.If need a four sections then return 4 in numberofsections. You can add the title to each sections as below and later add it to label in viewForHeaderInSection.You must provide the number of rows in each sections correctly.
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 4
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if(section == 0)
{
return "Section 0"
}
else if(section == 1)
{
return "Section 1"
}
else if(section == 2)
{
return "section 2"
}
else if(section == 3)
{
return "section 3"
}
return ""
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
switch(section)
{
case 0: //for first section
//return your count
case 1://Cells for
//return your count
case 2:
//return your count
case 3:
//return your count
default:
return 4
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! Cell1
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! Cell1
return cell
}
else if indexPath.section == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! Cell1
return cell
}
else if indexPath.section == 3 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! Cell1
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as? Cell2
//Set up labels etc.
return cell!
}
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 50))
headerView.layer.borderWidth = 2
let myLabel = UILabel()
myLabel.frame = CGRectMake(0, 0, tableView.frame.width - 70, 50)
myLabel.font = UIFont.boldSystemFontOfSize(18)
myLabel.textColor = UIColor.whiteColor()
myLabel.textAlignment = .Left
myLabel.text = " " + self.tableView(tableView, titleForHeaderInSection: section)!
headerView.addSubview(myLabel)
return headerView
}
If you are using .xib file then you should also register that file in viewDidLoad() as
self.tableView.registerNib(UINib(nibName: "cell1", bundle: nil), forCellReuseIdentifier: "cell1")
self.tableView.registerNib(UINib(nibName: "cell2", bundle: nil), forCellReuseIdentifier: "cell2")

How to display two arrays in two different cells in UITableView using swift3

I am trying to display two arrays in two different cells in a table view but it doesn't works , can any one help me to solve this problem , I am using Xcode8 and Swift3 , and this is my TableView code .
this is how I want to display the two arrays :
row1 = aaa
row2 = 11111
row3 = bbb
row4 = 2222
row5 = cccc
row6 = 3333
row7 = ddd
row8 = eee
row9 = fff
My code :
import UIKit
class _CellsTableViewController: UITableViewController {
var array1 = [String]()
var array2 = [String]()
override func viewDidLoad() {
super.viewDidLoad()
array1 = ["aaa","bbb","ccc","ddd","eee","fff"]
array2 = ["11111","22222","33333"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
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 {
return array1.count + array2.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = array1[indexPath.row]
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell.textLabel?.text = array2[indexPath.row]
return cell
}
}
}
make a single array with combination of two and then reload table. See the following code,
let array1 = ["aaa","bbb","ccc","ddd","eee","fff"]
let array2 = ["11111","22222","33333"]
var arrayAllItems = [String]()
for i in 0..<max(array1.count, array2.count){
if array1.count > i{
arrayAllItems.append(array1[i])
}
if array2.count > i{
arrayAllItems.append(array2[i])
}
}
Reload table with array arrayAllItems
I don't understand why you need to do this. But you code should be:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var index = indexPath.row/2;
if(index<array1.count %% index<array2.count)
{
if (indexPath.row % 2 == 0){
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = array1[index]
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell.textLabel?.text = array2[index]
return cell
}
}
else {
var isFirst
if(index>=array1.count)
{
index = indexPath.row - array1.count;
isFirst = false
}else
{
index = indexPath.row - array2.count;
isFirst = true
}
if(isFirst)
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = array1[index]
return cell
}else
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell.textLabel?.text = array2[index]
return cell
}
}
}
But I don't test this code.

Resources