I am trying to create expand/ collapse tableView having multiple labels, textViews and images. The problem is when I expand a cell, the top most label (Black Text/ Blue background in image) disappears and then comes back when cell updates. Is there any proper solution to fix this type of problem? Is this related to reloadRows?
// ViewController Class:
private func bindTableView() {
guard let tableView = self.planServicesTableView,
let viewModel = self.viewModel else {
return
}
tableView.estimatedRowHeight = 130
tableView.rowHeight = UITableView.automaticDimension
let dataSource = RxTableViewSectionedReloadDataSource<PlanServiceSection>(configureCell:
{(dataSource: TableViewSectionedDataSource<PlanServiceSection>,
tableView: UITableView,
indexPath: IndexPath,
item: PlanServiceSection.Item) -> UITableViewCell in
let cell = tableView.dequeueReusableCell(withIdentifier: item.cellType.cellIdent, for: indexPath)
if let planServiceCell = cell as? PlanServiceDescriptionTableViewCell {
planServiceCell.setCollapsed(collapsed:(viewModel.cellIsExpanded(at: indexPath)) ? false : true)
planServiceCell.configureCell(item: item)
planServiceCell.upgradeTextView.sizeToFit()
planServiceCell.featureDisclaimerTextView.sizeToFit()
}
if let disclaimerCell = cell as? PlanDisclaimerTableViewCell {
disclaimerCell.setCollapsed(collapsed: (viewModel.cellIsExpanded(at: indexPath)) ? false : true)
disclaimerCell.configureCell(item: item)
disclaimerCell.disclaimerDescriptionTextView.sizeToFit()
}
return cell
})
viewModel.dataSource = dataSource
tableView.tableFooterView = UIView()
tableView.delegate = self
viewModel.sections.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: self.disposeBag)
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let descriptionCell = tableView.cellForRow(at: indexPath) as? PlanServiceDescriptionTableViewCell {
descriptionCell.setCollapsed(collapsed: shouldCollapseCell(indexPath: indexPath))
}
if let disclaimerCell = tableView.cellForRow(at: indexPath) as? PlanDisclaimerTableViewCell {
disclaimerCell.setCollapsed(collapsed: shouldCollapseCell(indexPath: indexPath))
}
DispatchQueue.main.async {
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
private func shouldCollapseCell(indexPath: IndexPath) -> Bool {
if let isExpanded = viewModel?.cellIsExpanded(at: indexPath),
isExpanded {
self.viewModel?.removeExpandedIndexPath(indexPath)
return true
}
self.viewModel?.addExpandedIndexPath(indexPath)
return false
}
// TableViewCell Class:
func setCollapsed(collapsed: Bool) {
self.toggleArrowImage.image = (collapsed ? expandImage : collapseImage)
self.stackView.isHidden = collapsed
}
you need to do the following to fix it
var cellHeights:[IndexPath:CGFloat] = [ : ]
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeights[indexPath]{
return height
}
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeights[indexPath] = cell.frame.size.height
}
let me know once you have tested!
Related
I'm newer in xcode and swift and i found a guide for expand cell when the entire cell is pressed.
Now i wanna expand the cell when the button inside the cell is pressed.
I have this in my view controller :
//datasource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView.tag == 100 {
return nameArr.count
}else{
return prova.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 100 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
cell.lblName.text = nameArr[indexPath.row]
cell.expand.tag = indexPath.row
return cell
}else{
tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableView.automaticDimension
let cell = tableView.dequeueReusableCell(withIdentifier: "InsideTableViewCell") as! InsideTableViewCell
cell.lblInsideName.text = prova[indexPath.row]
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//se la cella è selezionata e deve essere tirata ancora giù ritorna 243 che sarebbe il valore della cella + l'immagine dentro da mostrare
if selectedIndex == indexPath.row && isCollapsed == true && tableView.tag == 100 {
return 375
}else {
//altrimenti se è gia collassata e ripremiamo sulla cella ritorna 50 e quindi richiude la cella
return 96
}
}
//delegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if selectedIndex == indexPath.row {
if self.isCollapsed == false {
self.isCollapsed = true
}else{
self.isCollapsed = false
}
}else{
self.isCollapsed = true
}
self.selectedIndex = indexPath.row
//tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.beginUpdates()
tableView.endUpdates()
}
But i don't know ho to do that.
In my viewController now i have this variable :
var selectedIndex = -1 //tell me which cell i pressed
var isCollapsed = false // tell if the cell is already collapsed
You can define a clouser in cell and call it when you press the button in your cell
in your cell define:
var buttonClicked: (() -> Void)?
in your cell button call this clouser
func buttonPressAction() {
buttonClicked?()
}
in your cellForRow method change it like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView.tag == 100 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
cell.buttonClicked = { [weak self] in
if self.isCollapsed == false {
self.isCollapsed = true
} else{
self.isCollapsed = false
}
}else{
self.isCollapsed = true
}
}
}
Modify the data source to change it
And of course the data source can be more complex it can be an object that contains whether or not to open the property
let nameArr:[Bool] = [false, false, false]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.nameArr[indexPath.row] = !self.nameArr[indexPath.row]
tableView.reloadRows(at: [indexPath], with: .none)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let isshow = self.nameArr[indexPath.row]
if isshow {
return 375
} else {
return 69
}
}
You should update the table view after changing the height:
tableView.reloadData().
You can do it by sending info about that action to the view controller using delegates.
1) You should save a state of your cells. You can store it in the cell model:
class YourCellModel {
var isExpanded = false
}
2) You should create a delegate protocol:
protocol YourCellDelegate: AnyObject {
func buttonPressed()
}
3) Add properties for the cell delegate and the cell model. Also you should add a function buttonPressed:
class YourCell: UITableViewCell {
weak var delegate: YourCellDelegate?
var model: YourCellModel?
//...
#IBAction func buttonPressed() {
model?.isExpanded = true
delegate?.buttonPressed()
}
}
4) You should store cell models in the view controller: {
class YourViewController: UIViewController {
var cellModels: [YourCellModel] = []
//...
override func viewDidLoad() {
super.viewDidLoad()
cellModels = Array(repeating: YourCellModel(), count: <count of cells, maybe it is a prova.count>)
}
}
5) Setup cell models and delegates to the cells in cellForItem:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = cellModels[indexPath.row]
if tableView.tag == 100 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
cell.lblName.text = nameArr[indexPath.row]
cell.expand.tag = indexPath.row
cell.model = model
cell.delegate = self
return cell
} else {
tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableView.automaticDimension
let cell = tableView.dequeueReusableCell(withIdentifier: "InsideTableViewCell") as! InsideTableViewCell
cell.lblInsideName.text = prova[indexPath.row]
cell.model = model
cell.delegate = self
return cell
}
}
6) Update heightForItem:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let model = cellModels[indexPath.row]
if model.isExpanded {
return 375
} else {
return 96
}
}
7) Your view controller should implement YourCellDelegate:
extension YourViewController: YourCellDelegate {
func buttonPressed() {
tableView.reloadData()
}
}
I have attached the image click the card view expands the same card inside the table cell dynamically its passible to achieve this?
I have searched a lot but not working
Hear my code added header cell with CardView
added arrow button to click the button expand the cell
its able expand but not in parent card it was showing diff card
I have adde my source code
var hiddenSections = Set<Int>()
let tableViewData = [
["1","2","3","4","5"],
["1","2","3","4","5"],
["1","2","3","4","5"],
]
override func viewDidLoad() {
super.viewDidLoad()
let CustomeHeaderNib = UINib(nibName: "CustomSectionHeader", bundle: Bundle.main)
historyTableView.register(CustomeHeaderNib, forHeaderFooterViewReuseIdentifier: "customSectionHeader")
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.tableViewData.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.hiddenSections.contains(section) {
return 0
}
return self.tableViewData[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = self.tableViewData[indexPath.section][indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return view.frame.width/4
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = self.historyTableView.dequeueReusableHeaderFooterView(withIdentifier: "customSectionHeader") as! CustomSectionHeader
header.setupCornerRadious()
let sectionButton = header.expandBtn
sectionButton?.setTitle(String(section),
for: .normal)
sectionButton?.tag = section
sectionButton?.addTarget(self,action: #selector(self.hideSection(sender:)), for: .touchUpInside)
return header
}
#objc
private func hideSection(sender: UIButton) {
let section = sender.tag
func indexPathsForSection() -> [IndexPath] {
var indexPaths = [IndexPath]()
for row in 0..<self.tableViewData[section].count {
indexPaths.append(IndexPath(row: row,
section: section))
}
return indexPaths
}
if self.hiddenSections.contains(section) {
self.hiddenSections.remove(section)
self.historyTableView.insertRows(at: indexPathsForSection(),
with: .fade)
} else {
self.hiddenSections.insert(section)
self.historyTableView.deleteRows(at: indexPathsForSection(),
with: .fade)
}
}
With out sections also you can achieve this. To do this,
1.Return cell height as section height. If user clicks on the cell then return total content height to the particular cell.
2.You need to take an array, if user selects cell, add indexPath number in to array. If selects already expand cell remove it from array. In height for row at index check indexPath is in array or not.
This is one of the way. With sections also you can do that.
//MARK:- UITableView Related Methods
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrDict.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
// var cel = tblExpandedTest.dequeueReusableCellWithIdentifier("expCell", forIndexPath: indexPath) as! CDTableViewCell
var cel : CaseHearingTabTVC! = tableView.dequeueReusableCell(withIdentifier: "caseHearingTabCell") as! CaseHearingTabTVC
if(cel == nil)
{
cel = Bundle.main.loadNibNamed("caseHearingTabCell", owner: self, options: nil)?[0] as! CaseHearingTabTVC;
}
//cell?.backgroundColor = UIColor.white
cel.delegate = self
if indexPath != selctedIndexPath{
cel.subview_desc.isHidden = true
cel.subview_remarks.isHidden = true
cel.lblHearingTime.isHidden = true
}
else {
cel.subview_desc.isHidden = false
cel.subview_remarks.isHidden = false
cel.lblHearingTime.isHidden = false
}
return cel
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectIndex = true;
if(selectedInd == indexPath.row) {
selectedInd = -1
}
else{
let currentCell = tableView.cellForRow(at: indexPath)! as! CaseHearingTabTVC
cellUpdatedHeight = Float(currentCell.lblHearingTime.frame.origin.y + currentCell.lblHearingTime.frame.size.height) + 2;
selectedInd = -1
tblCaseHearing.reloadData()
selectedInd = indexPath.row
}
let previousPth = selctedIndexPath
if indexPath == selctedIndexPath{
selctedIndexPath = nil
}else{
selctedIndexPath = indexPath
}
var indexPaths : Array<IndexPath> = []
if let previous = previousPth{
indexPaths = [previous]
}
if let current = selctedIndexPath{
indexPaths = [current]
}
if indexPaths.count>0{
tblCaseHearing.reloadRows(at: indexPaths, with: UITableView.RowAnimation.automatic)
}
}
func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowIndexPath indexPath:IndexPath) {
(cell as! CaseHearingTabTVC).watchFrameChanges()
}
func tableView(_ tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowIndexPath indexPath:IndexPath) {
(cell as! CaseHearingTabTVC).ignoreFrameChanges()
}
func tableView(_ TableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
if indexPath == selctedIndexPath{
return CGFloat(cellUpdatedHeight)
}else{
return CaseHearingTabTVC.defaultHeight
}
}
Best approach is to create two different cells for normal card and expanded card.
fileprivate var selectedIndex: Int?
func registerTableViewCells() {
tableView.register(UINib(nibName:Nib.CardCell , bundle: nil), forCellReuseIdentifier: "CardCell")
tableView.register(UINib(nibName:Nib.ExpandedCardCell , bundle: nil), forCellReuseIdentifier: "ExpandedCardCell")
}
override func viewDidLoad() {
super.viewDidLoad()
self.registerTableViewCells()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let index = selectedIndex else {
return 115
}
if index == indexPath.row{
return 200
}
return 115
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let selected = selectedIndex, selected == indexPath.row{
let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandedCardCell", for: indexPath) as! ExpandedCardCell
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedIndex == indexPath.row{
selectedIndex = nil
}
else{
selectedIndex = indexPath.row
}
UIView.performWithoutAnimation {
tableView.reloadData()
}
}
I changing textlabel color on didSelectRowAt but when I scroll UITableView it also effects in other textlabel also
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
if (cell.LBLIntrest.textColor == (UIColor.black))
{
cell.LBLIntrest.textColor = Uicolor.blue
} else {
cell.LBLIntrest.textColor = Uicolor.black
}
}
First you have to create property to hold selected cell like below
/* To hold selected cell */
var selectedIndexPath :IndexPath?
After that set color of selected cell in cellForRowAt
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") {
cell.textLabel?.text = "Row Number: \(indexPath.row)"
/* Check if cell is selected then set layout accourding to your requirements */
if indexPath == selectedIndexPath {
cell.textLabel?.textColor = .blue
} else {
cell.textLabel?.textColor = .black
}
return cell
}
return UITableViewCell()
}
After this manage when user select a cell in didSelectRowAt
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Toggle if user seleted same cell
if selectedIndexPath == indexPath {
if let cell = tableView.cellForRow(at: indexPath) {
/* Check and toggle selected cell color */
cell.textLabel?.textColor = cell.textLabel?.textColor == .black ? .blue : .black
}
} else {
/* set color of seleted cell */
if let cell = tableView.cellForRow(at: indexPath) {
cell.textLabel?.textColor = .blue
}
}
/* Save which cell is selected */
selectedIndexPath = indexPath
}
And last manage didDeselectRowAt
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
/* Remove if deselect same cell */
if selectedIndexPath == indexPath {
selectedIndexPath = nil
}
/* Change color to black */
if let cell = tableView.cellForRow(at: indexPath) {
cell.textLabel?.textColor = .black
}
}
This code is for on cell selection at one time so you have to set
tableView.allowsMultipleSelection = false
Hope this helps.
This should work for you.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
setSelectedColor(cell: cell)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
...
if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
setSelectedColor(cell: cell)
}
return cell
}
func setSelectedColor(cell: UITableViewCell) {
if (cell.LBLIntrest.textColor == (UIColor.black)) {
cell.LBLIntrest.textColor = Uicolor.blue
} else {
cell.LBLIntrest.textColor = Uicolor.black
}
}
But, I would recommend moving that cell.LBLIntrest.textColor = Uicolor.blue to UITableViewCell under func setSelected(_ selected: Bool, animated: Bool) method
class TableViewCell: UITableViewCell {
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// label textColor logic goes here
// make use of selected
}
}
I have a table view. I am using multiple cell selection. Everything is working correctly, functionality wise, but UI wise it is not. Whenever I select a cell and scroll down I see the color is changed in another cell below though that cell was never actually selected. What I have done is this for the cell:
class FollowSportsCell: UITableViewCell {
#IBOutlet weak var sportL: UILabel!
#IBOutlet weak var backImg: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
super.prepareForReuse()
backImg.backgroundColor = UIColor(hexString: "E6E6E6")
sportL.textColor = .black
}
And, here are delegates.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sportsArr!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as! FollowSportsCell
let sport = sportsArr![indexPath.row]["id"] as! Int
cell.sportL.text = sportsArr![indexPath.row]["title"] as? String
cell.selectionStyle = UITableViewCell.SelectionStyle.none
if selectedSports.contains(sport) {
cell.sportL.textColor = .white
cell.backImg.backgroundColor = UIColor(hexString: "4293CC")
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCell += 1
let sport = sportsArr![indexPath.row]["id"]
selectedSports.append(sport! as! Int)
if selectedCell > 1
{
collectionB[0].backgroundColor = UIColor(hexString: "4293CC")
collectionB[0].isEnabled = true
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
selectedCell -= 1
selectedSports = selectedSports.filter{$0 != sportsArr![indexPath.row]["id"] as! Int}
if selectedCell < 2
{
collectionB[0].backgroundColor = .lightGray
collectionB[0].isEnabled = false
}
}
When, the number is low like 4 or 5 and the scroll doesn't appear everything is good, but once they are like 20-22 then, I get this issue. Any help?
You should handle background color in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) .
Check and use below code. Hope it will work
var selectedCells = Array<NSInteger>()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sportsArr!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as! FollowSportsCell
cell.sportL.text = sportsArr![indexPath.row]["title"] as? String
cell.selectionStyle = UITableViewCell.SelectionStyle.none
if self.selectedCells.contains(indexPath.row) {
cell.sportL.textColor = .white
cell.backImg.backgroundColor = UIColor(hexString: "4293CC")
if self.selectedCells.count > 1
{
collectionB[0].backgroundColor = UIColor(hexString: "4293CC")
collectionB[0].isEnabled = true
}
}
else
{
//Here Set your default color for cell backImgr background color
cell.sportL.textColor = // set default color
cell.backImg.backgroundColor = // set default color
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! FollowSportsCell
if self.selectedCells.contains(indexPath.row) {
//Here you will get selected cell and going to deselect...Do anything with deselection
if let index = self.selectedCells.index{$0 == indexPath.row}
{
self.selectedCells.remove(at: index)
}
cell.sportL.textColor = .black
cell.backImg.backgroundColor = UIColor(hexString: "E6E6E6")
selectedCell -= 1
selectedSports = selectedSports.filter{$0 != sportsArr![indexPath.row]["id"] as! Int}
if self.selectedCells.count < 2
{
collectionB[0].backgroundColor = .lightGray
collectionB[0].isEnabled = false
}
}
else
{
self.selectedCells.append(indexPath.row)
print(cell.sportL.text!)
selectedCell += 1
let sport = sportsArr![indexPath.row]["id"]
selectedSports.append(sport! as! Int)
}
self.yourtblView.reloadData()
}
Please select your default and selected color in "CellForRowAtIndexPAth". Please check the below code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as! FollowSportsCell
cell.sportL.text = sportsArr![indexPath.row]["title"] as? String
cell.selectionStyle = UITableViewCell.SelectionStyle.none
let sport = sportsArr![indexPath.row]["id"]
cell.sportL.textColor = default cell colour
cell.backImg.backgroundColor = default cell colour
if selectedSports.contain(sport) {
cell.sportL.textColor = required cell colour
cell.backImg.backgroundColor = required cell colour
}
return cell
}
import UIKit
class TableVC: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView : UITableView!
var arrayOfTitle : [titleOfArray] = [titleOfArray]()
override func viewDidLoad() {
super.viewDidLoad()
if self.tableView != nil {
self.tableView.delegate = self
self.tableView.dataSource = self
}
for i in 0...20 {
self.arrayOfTitle.append(titleOfArray(title: "Test\(i)", isSelectedIndex: false))
}
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrayOfTitle.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel!.text = self.arrayOfTitle[indexPath.row].title
cell?.textLabel!.textColor = self.arrayOfTitle[indexPath.row].isSelectedIndex ? UIColor.red : UIColor.blue
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
for i in 0...self.arrayOfTitle.count-1 {
self.arrayOfTitle[i].isSelectedIndex = false
}
self.arrayOfTitle[indexPath.row].isSelectedIndex = true
tableView.reloadData()
}
}
class titleOfArray : NSObject {
var title : String!
var isSelectedIndex : Bool!
init(title:String! ,isSelectedIndex :Bool) {
self.title = title
self.isSelectedIndex = isSelectedIndex
}
}
this might be helpful
I have made a drop down gender which is working fine however I have another drop down on same viewcontroller which shows drop down but when I select the item it gives error fatal error: unexpectedly found nil while unwrapping an Optional value I have tried out but confused. help me to solve the bloodList dropdown.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var genderButton: UIButton!
#IBAction func genderButton(_ sender: Any) {
self.PressDrop()
view.addSubview(genderTable)
}
#IBOutlet weak var genderTable: UITableView!
var flag = 1
var dropDownList = [String]()
#IBOutlet weak var bloodButton: UIButton!
var bloodList = [String]()
#IBAction func bloodButton(_ sender: Any) {
self.PressBlood()
view.addSubview(bloodTable)
}
#IBOutlet weak var bloodTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
dropDownList = ["Male", "Female", "Other"]
genderTable.delegate = self
genderTable.dataSource = self
genderTable.isHidden = true
view.addSubview(genderTable)
genderTable.layer.cornerRadius = 10
bloodList = ["A+", "A-", "AB+", "AB-"]
bloodTable.delegate = self
bloodTable.dataSource = self
bloodTable.isHidden = true
view.addSubview(bloodTable)
bloodTable.layer.cornerRadius = 10
}
func PressDrop() {
if flag == 0 {
UIView.setAnimationDuration(0.5)
self.genderTable.isHidden = true
self.flag = 1
}
else{
UIView.setAnimationDuration(0.5)
self.genderTable.isHidden = false
self.flag = 0
}
}
func PressBlood() {
if flag == 0 {
UIView.setAnimationDuration(0.5)
self.bloodTable.isHidden = true
self.flag = 1
}
else{
UIView.setAnimationDuration(0.5)
self.bloodTable.isHidden = false
self.flag = 0
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dropDownList.count
}
func tableViewBlood(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return bloodList.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = genderTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel!.text = dropDownList[indexPath.row]
return cell
}
func tableViewTwo(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = bloodTable.dequeueReusableCell(withIdentifier: "bloodCell", for: indexPath)
cell.textLabel!.text = bloodList[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedData = dropDownList[indexPath.row]
genderButton.setTitle(selectedData, for: .normal)
self.genderTable.isHidden = true
self.flag =
let indexPath = genderTable.indexPathForSelectedRow
let currentCell = genderTable.cellForRow(at: indexPath!)! as UITableViewCell
let finalresult = currentCell.textLabel!.text!
print("\(finalresult)")
}
private func tableViewTwo(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedBlood = bloodList[indexPath.row]
bloodButton.setTitle(selectedBlood, for: .normal)
self.bloodTable.isHidden = true
self.flag = 1
let indexPathTwo = bloodTable.indexPathForSelectedRow
let currentCellBlood = bloodTable.cellForRow(at: indexPathTwo!)! as UITableViewCell
let finalresultBlood = currentCellBlood.textLabel!.text!
print("\(finalresultBlood)")
}
}
You cannot change default delegate methods of your tableView, give conditions in the delegate methods like below :
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == genderTable {
return dropDownList.count
}
return bloodList.count
}
Also make similar changes in the remaining delegate methods.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == genderTable {
let cell = genderTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel!.text = dropDownList[indexPath.row]
return cell
} else {
let cell = bloodTable.dequeueReusableCell(withIdentifier: "bloodCell", for: indexPath)
cell.textLabel!.text = bloodList[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == genderTable {
let selectedData = dropDownList[indexPath.row]
genderButton.setTitle(selectedData, for: .normal)
self.genderTable.isHidden = true
let currentCell = genderTable.cellForRow(at: indexPath)! as UITableViewCell
let finalresult = currentCell.textLabel!.text!
print("\(finalresult)")
} else {
let selectedBlood = bloodList[indexPath.row]
bloodButton.setTitle(selectedBlood, for: .normal)
self.bloodTable.isHidden = true
let currentCellBlood = bloodTable.cellForRow(at: indexPath)! as UITableViewCell
let finalresultBlood = currentCellBlood.textLabel!.text!
print("\(finalresultBlood)")
}
}
Don't create like this
func tableViewTwo(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell (This will consider as new method to your current class)
They are all in build delegate methods of UITableview, you should override it, you cannot change it.
Instead of creating method, you try with Bool variable in respective button action.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
If isDrop == true{
return dropDownList.count
}else{
return bloodList.count
}
}
Like change the condition
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
I waited for an answer but did not find :( that's ok . I thought a number of times and then come to this code yahoooo!!! then i believed i am really a programmer. Actually i did not defined the condition for each table view so i was in nightmare. This code is pure programatically and does not require any irritating third party library or awkward pods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == tableViewB {
return dropDownList.count
}
else {
return genderL.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableViewB {
let cell = tableViewB.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel!.text = dropDownList[indexPath.row]
return cell
}
else {
let cell = genderT.dequeueReusableCell(withIdentifier: "gender", for: indexPath)
cell.textLabel!.text = genderL[indexPath.row]
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == tableViewB {
let selectedData = dropDownList[indexPath.row]
buttonB.setTitle(selectedData, for: .normal)
self.tableViewB.isHidden = true
self.flag = 1
let indexPath = tableViewB.indexPathForSelectedRow
let currentCell = tableViewB.cellForRow(at: indexPath!)! as UITableViewCell
let finalresult = currentCell.textLabel!.text!
print("\(finalresult)")
}
else {
let selectedDataG = genderL[indexPath.row]
genderB.setTitle(selectedDataG, for: .normal)
self.genderT.isHidden = true
self.flag = 1
let indexPath = genderT.indexPathForSelectedRow
let currentCell = genderT.cellForRow(at: indexPath!)! as UITableViewCell
let finalresult = currentCell.textLabel!.text!
print("\(finalresult)")
}
}