How to manage with custom SegmentControllCell to tableview cell? - ios

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

Related

How to show array of array json in tableview using Swift?

Now my ViewController code is here -
import UIKit
struct jsonstruct: Codable {
let name: String
let meta_data: [Categories]
enum CodingKeys: String, CodingKey {
case name
case meta_data
}
}
struct Categories: Codable {
let value: String
enum CodingKeys: String, CodingKey {
case value
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var arrdata : [jsonstruct] = [jsonstruct]()
var categorydata : [Categories] = [Categories]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getdata()
}
func getdata() {
let url = URL(string: "https://mywebstaging.net/ab/garnier/wp-json/wc/v3/products?consumer_key=<key>&consumer_secret=<secret>")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do{if error == nil{
self.arrdata = try JSONDecoder().decode([jsonstruct].self, from: data!)
print(self.arrdata)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print("Error in get json data")
}
}.resume()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == tableView {
return arrdata.count
}else{
return categorydata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdatadesciption = self.categorydata[indexPath.row]
cell.lblname.text = getdatadesciption.value
return cell
}
}
}
Hare only the "name" is being displayed in the tableview. But the "value" is not coming. The output I'm getting like this. Please guide me. Thanks in advance.
Replace
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdatadesciption = self.categorydata[indexPath.row]
cell.lblname.text = getdatadesciption.value
return cell
}
with getdata.meta_data.first?.value contains top category name
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
cell.lblname.text = getdata.meta_data.first?.value
return cell
You don't have to maintain 2 arrays it's only one
Replace
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == tableView {
return arrdata.count
} else {
return categorydata.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdata = arrdata[indexPath.row]
cell.lblid.text = getdata.name
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let getdatadesciption = self.categorydata[indexPath.row]
cell.lblname.text = getdatadesciption.value
return cell
}
}
With
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrdata.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CellTableViewCell
let data = arrdata[indexPath.row]
let category = data.meta_data.first
cell.lblid.text = data.name
cell.lblname.text = category.value
return cell
}

Use two different custom UITableView Cells

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

UITableView inside a UICollectionView: can't set value

I have a UICollectionView with 4 UICollectionViewCells. Each cell contains a UITableView with a varying number of cells.
I have an array from which I need to pass a value (depending on the indexPath) into the cell. My problem is that it always gives me nil when I try to do this.
So for example I have this array:
let arrayOfStrings = ["test1", "test2", "test3", "test4"]
I have this code in my collection view's cellForItemAt method:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCollectionViewCell", for: indexPath) as! TestCollectionViewCell
cell.myString = arrayOfStrings[indexPath.row]
cell.label.text = "This text is set."
return cell
}
The cell's label is set properly, but when I try to print myString in the cell's table view's cellForRowAt method it always returns nil.
I need the string because I plan to manipulate the table views depending on the string passed in.
So why is this happening and what can be done?
You can try like this
extension HomeViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DealTableViewCell", for: indexPath) as! DealTableViewCell
cell.DealCollectionView.dataSource = self
cell.DealCollectionView.delegate = self
cell.DealCollectionView.tag = 10101
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "BusinessTableViewCell", for: indexPath) as! BusinessTableViewCell
cell.BusinessCollectionView.dataSource = self
cell.BusinessCollectionView.delegate = self
cell.BusinessCollectionView.tag = 10102
return cell
} else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCell(withIdentifier: "FilterTableViewCell", for: indexPath) as! FilterTableViewCell
cell.FilterCollectionView.dataSource = self
cell.FilterCollectionView.delegate = self
cell.FilterCollectionView.tag = 10103
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "ComboTableViewCell", for: indexPath) as! ComboTableViewCell
cell.ComboCollectionView.dataSource = self
cell.ComboCollectionView.delegate = self
cell.ComboCollectionView.tag = 10104
return cell
}
}
}
Add the collection view to each tableview cell and set delegate in tableview cell
extension HomeViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 10101 {
return 3
} else if collectionView.tag == 10102 {
return 3
} else if collectionView.tag == 10103 {
return 3
} else if collectionView.tag == 10104 {
return 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 10101 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "DealCollectionViewCell", for: indexPath) as! DealCollectionViewCell
return cell
} else if collectionView.tag == 10102 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "BusinessCollectionViewCell", for: indexPath) as! BusinessCollectionViewCell
return cell
} else if collectionView.tag == 10103 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "FilterCollectionViewCell", for: indexPath) as! FilterCollectionViewCell
return cell
} else if collectionView.tag == 10104 {
let cell = collectionView.dequeueReusableCell(withIdentifier: "ComboCollectionViewCell", for: indexPath) as! ComboCollectionViewCell
return cell
}
return UICollectionViewCell()
}
}
For reload the collectionView in use
if let cell = self.tableView.cellForRow(at: IndexPath(row: i, section: 0)) as?
tableViewCell {
cell.collectionView.reloadData()
}

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!

Swift 3.0 How to Change a Button Title Using TableView Cells

I have a table view with subclassed table view cells. I have attached a button and hooked this up to the table view cell's VC. I want the button to say 'Add' upon loading, 'Subtract' when clicked and back to 'Add' when clicked again. But I am having trouble understanding how I can relate the row number with the state of the button.
VC with table view:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TVCell
cell.cellDelegate = self
if (searchActive) {
cell.textLabel?.text = filtered[indexPath.row]
} else {
cell.textLabel?.text = data[indexPath.row]
}
return cell
}
func didPressButton(cell: TVCell) {
guard let indexPath = self.tableView.indexPath(for: cell) else {
return
}
print("Button tapped on row \(indexPath.row)")
}
VC for table view cell:
protocol TVCellDelegate : class {
func didPressButton(cell: TVCell)
}
class TVCell: UITableViewCell {
#IBOutlet weak var addButton: UIButton!
weak var cellDelegate: TVCellDelegate?
override func prepareForReuse() {
super.prepareForReuse()
self.cellDelegate = nil
}
// connect the button from your cell with this method
#IBAction func buttonPressed(sender: UIButton) {
self.cellDelegate?.didPressButton(cell: self)
}
}
Store the buttons' state in your view controller and change the text after reusing and button pressing.
VC with TableView:
var isSubtracting = [IndexPath: Bool]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TVCell
cell.cellDelegate = self
if isSubtracting[indexPath] ?? false {
cell.addButton.setTitle("Add", for: .normal)
} else {
cell.addButton.setTitle("Subtract", for: .normal)
}
cell.indexPath = indexPath
if(searchActive) {
cell.textLabel?.text = filtered[indexPath.row]
} else {
cell.textLabel?.text = data[indexPath.row]
}
return cell
}
func didPressButton(indexPath: IndexPath) {
guard let cell = tableView.cellForRow(at: indexPath) as? TVCell else {
return
}
if isSubtracting[indexPath] ?? false {
isSubtracting[indexPath] = false
cell.addButton.setTitle("Subtract", for: .normal)
} else {
isSubtracting[indexPath] = true
cell.addButton.setTitle("Add", for: .normal)
}
}
VC for table view cell:
protocol TVCellDelegate : class {
func didPressButton(indexPath: IndexPath)
}
class TVCell: UITableViewCell {
#IBOutlet weak var addButton: UIButton!
weak var cellDelegate: TVCellDelegate?
var indexPath: IndexPath!
override func prepareForReuse() {
super.prepareForReuse()
self.cellDelegate = nil
}
// connect the button from your cell with this method
#IBAction func buttonPressed(sender: UIButton) {
self.cellDelegate?.didPressButton(indexPath: indexPath)
}
}
You can add the title's for the states of buttons like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TVCell
cell.cellDelegate = self
cell.indexPath = indexPath
cell.addButton.setTitle("Add",for: .normal)
cell.addButton.setTitle("Subtract",for: .selected)
if(searchActive) {
cell.textLabel?.text = filtered[indexPath.row]
} else {
cell.textLabel?.text = data[indexPath.row]
}
return cell
}
and tableViewCell
protocol TVCellDelegate : class {
func didPressButton(indexPath: IndexPath)
}
class TVCell: UITableViewCell {
#IBOutlet weak var addButton: UIButton!
weak var cellDelegate: TVCellDelegate?
var indexPath: IndexPath!
override func prepareForReuse() {
super.prepareForReuse()
self.cellDelegate = nil
}
// connect the button from your cell with this method
#IBAction func buttonPressed(sender: UIButton) {
if(sender.isSelected){
sender.isSelected = false
}else{
sender.isSelected = true
}
self.cellDelegate?.didPressButton(indexPath: indexPath)
}
}

Resources