I have embed a UISwitch on a UITableView cell.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
if self.users.count > 0 {
let eachPost = self.users[indexPath.row]
let postDate = (eachPost.date as? String) ?? ""
let postTitle = (eachPost.title as? String) ?? ""
cell.detailTextLabel?.text = postDate
cell.textLabel?.text = postTitle
}
if cell.accessoryView == nil{
let switchView : UISwitch = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
}
return cell
}
My table has 30 rows. When I select a switch on the visible cells and then scroll down, on the cells from the bottom of the list the switch is selected by default. What can I do to have correct selections for my list?
My solution without creating a custom class:
class MyTableViewController: UITableViewController {
var users: [[String: Any]] = [[String: Any]]()
// This array is used for storring the state for switch from each cell. Otherwise when the cell is reused the state is displayed incorrectly
var switchArray = [Bool]()
override func viewDidLoad() {
super.viewDidLoad()
self.users = result
for _ in 0 ..< self.users.count {
self.switchArray.append(false)
}
self.tableView?.reloadData()
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let eachPost = self.users[indexPath.row]
let postTitle = (eachPost.title as? String) ?? ""
cell.textLabel?.text = postTitle
let switchView : UISwitch = UISwitch(frame: .zero)
switchView.isOn = self.switchArray[indexPath.row]
cell.accessoryView = switchView
return cell}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
self.switchArray[indexPath.row] = true
let switchView : UISwitch = (tableView.cellForRow(at: indexPath)?.accessoryView) as! UISwitch;
switchView.isOn = true
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.switchArray[indexPath.row] = false
let switchView : UISwitch = (tableView.cellForRow(at: indexPath)?.accessoryView) as! UISwitch;
switchView.isOn = false
}
Note: Multiple selection has to be enabled
Related
I am trying the to reload the tableview whenever the didset is countRow is called. It has never worked.
I have tried guard and if let in the didset, it has never work out.
I realised it is calling another object of tableview. it is very weird,
import UIKit
class ViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {
// Global Variable
var tableView: UITableView!
var tableView2 : UITableView!
var countRow : Int = 0 {
didSet{
//if let tableview == tableview
guard tableView2 == tableView else
{
tableView2 = UITableView(frame: self.view.bounds)
tableView2.delegate = self
tableView2.dataSource = self
self.tableView2.reloadData()
self.tableView.reloadData()
print ("3countRow: \(countRow)")
return
}
self.tableView2.reloadData()
self.tableView.reloadData()
print ("2countRow: \(countRow)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: self.view.bounds)
tableView.delegate = self
tableView.dataSource = self
self.view.addSubview(tableView)
tableView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
tableView.register(TableViewCell.self, forCellReuseIdentifier: "TableViewCell")
tableView.register(AppCell.self, forCellReuseIdentifier: "NormalCell")
tableView.register(appDays.self, forCellReuseIdentifier: "textField")
tableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print (countRow)
return 5 + countRow
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "NormalCell", for: indexPath) as! AppCell
cell.backgroundColor = UIColor.groupTableViewBackground
return cell
}
if indexPath.row == 1 || indexPath.row == 2
{
var cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
cell.backgroundColor = UIColor.groupTableViewBackground
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "textField", for: indexPath) as! appDays
cell.backgroundColor = UIColor.groupTableViewBackground
return cell
}
}
countrow will be printed in the program
You never set countRow to a value. You only add 5 + countRow which does not mean you set 5 in countRow.
didSet is called immediately after the new value is stored. Swift official documentation
I'm using two table view in one view controller to populate my different data. All the other delegates methods are working fine but didselect method is not performing an action neither its printing any value in console. I hae checked through story board also all the things looks fine and i have set its delegate and datasources methods also but still it isn't working. Searched a lot from net but still unsuccessful in it. My code is this,
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = true
self.searchBar.delegate = self
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(LoginViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
dishDetailTableView.delegate = self
dishDetailTableView.dataSource = self
self.addOnTableView.allowsMultipleSelection = true
addOnTableView.delegate = self
addOnTableView.dataSource = self
dishDetailTableView.reloadData()
sectionArray = [String(MenuService.instance.subCategoryModelInstance[0].sub_categoryName)]
print(sectionArray)
cancelBtn.cornerButton()
cancelBtn.layer.borderColor = #colorLiteral(red: 1, green: 0, blue: 0.03742904276, alpha: 1)
cancelBtn.layer.borderWidth = 1.5
nextBtn.layer.borderColor = #colorLiteral(red: 0.09759091236, green: 0.5779017098, blue: 1, alpha: 1)
nextBtn.layer.borderWidth = 1.5
nextBtn.cornerButton()
menuTypeLbl.layer.cornerRadius = 5
addOnView.borderView(view: addOnView)
addOnView.isHidden = true
shadowView.isHidden = true
}
extension DishDetailViewController : UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
var count:Int?
if tableView == dishDetailTableView {
count = MenuService.instance.subCategoryItemModelInstance.count
}
if (tableView == addOnTableView) {
count = AddOnService.instance.AddOnModelInstance.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell:UITableViewCell?
if tableView == dishDetailTableView{
let cell = tableView.dequeueReusableCell(withIdentifier: "menuCell", for: indexPath) as! MenuDetailTableViewCell
cell.titleLbl?.text = MenuService.instance.subCategoryItemModelInstance[indexPath.row].itemName
cell.descriptionLbl?.text = MenuService.instance.subCategoryItemModelInstance[indexPath.row].itemdescription
cell.priceLbl?.text = MenuService.instance.subCategoryItemModelInstance[indexPath.row].itemprice
cell.backgroundColor = UIColor.clear
cell.delegate = self
cell.selectionStyle = .none
return cell
}
if tableView == addOnTableView{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! AddOnTableViewCell
cell.addOnLbl.text = AddOnService.instance.AddOnModelInstance[indexPath.row].itemName
print(cell.addOnLbl?.text! as Any)
return cell
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == dishDetailTableView{
print("Hi")
dishDetailTableView.reloadData()
}
if tableView == addOnTableView {
print("Hello")
addOnTableView.reloadData()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var count : Int?
if tableView == dishDetailTableView{
count = 120
}
if tableView == addOnTableView{
count = 60
}
return CGFloat(count!)
}
}
How can i perform any action on cell?
So Im attempting to create a multiple line text for the suitable cell detailedTitle however when I set the cell.numberOfLines = 0 I get multiple lines but without correct spacings for the cells. I have also tried calling cellAutoDimentions but it made no difference
cell.detailTextLabel?.numberOfLines = 0
I Get the following result when I run that code in my program
enter image description here
as you can see the text if getting pushed out of the cell's bounds in this case I'm talking about the top and bottom not the right side, that issue i know how to fix by changing the CGRect. Also the code doesn't allow for more than 2 lines
UPDATE:
The following is the entire section of my code
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itorStorage.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.messageField.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MessageCustomCell
cell.backgroundColor = LightBlue
cell.textLabel?.text = itorStorage[indexPath.row].name
cell.textLabel?.textColor = .white
cell.detailTextLabel?.text = itorStorage[indexPath.row].text
cell.detailTextLabel?.textColor = .white
cell.pic.image = itorStorage[indexPath.row].image
cell.timeStamp.text = itorStorage[indexPath.row].time
cell.detailTextLabel?.numberOfLines = 0
cell.detailTextLabel?.lineBreakMode = .byWordWrapping
return cell
}
override init() {
super.init()
messageField.delegate = self
messageField.dataSource = self
messageField.tableFooterView = UIView(frame: CGRect.zero)
messageField.rowHeight = UITableViewAutomaticDimension
messageField.allowsSelection = false
self.messageField.register(MessageCustomCell.self, forCellReuseIdentifier: "Cell")
ratingView.didFinishTouchingCosmos = didTouchCosmos
}
I think you need to implement estimatedHeightForRowAt as well as setting rowHeight to UITableViewAutomaticDimension. Something like this:
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 120.0
}
well i create tableview and inside of it tableview cell with xib file
now i want create tableview inside xib file , the main problem is that u can't create cell inside of it to define the identifier for this cell
i keep get this error
'unable to dequeue a cell with identifier AutoCompleteRowIdentifier -
must register a nib or a class for the identifier or connect a
prototype cell in a storyboard'
this is my code
import UIKit
class TableViewCell2: UITableViewCell, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var autocompleteTableView: UITableView!
var pastUrls = ["Men", "Women", "Cats", "Dogs", "Children"]
var autocompleteUrls = [String]()
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
autocompleteTableView.hidden = false
let substring = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
searchAutocompleteEntriesWithSubstring(substring)
return true // not sure about this - could be false
}
func searchAutocompleteEntriesWithSubstring(substring: String)
{
autocompleteUrls.removeAll(keepCapacity: false)
for curString in pastUrls
{
var myString:NSString! = curString as NSString
var substringRange :NSRange! = myString.rangeOfString(substring)
if (substringRange.location == 0)
{
autocompleteUrls.append(curString)
}
}
autocompleteTableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return autocompleteUrls.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let autoCompleteRowIdentifier = "AutoCompleteRowIdentifier"
let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier(autoCompleteRowIdentifier, forIndexPath: indexPath) as UITableViewCell
let index = indexPath.row as Int
cell.textLabel!.text = autocompleteUrls[index]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell : UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
textField.text = selectedCell.textLabel!.text
}
override func awakeFromNib() {
super.awakeFromNib()
textField.delegate = self
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}}
as you know you can't define identifier inside xib file
thanks
You need to register a cell with autocompleteTableView before you can dequeue it. Modify your code like this:
override func awakeFromNib() {
super.awakeFromNib()
textField.delegate = self
autocompleteTableView.delegate = self
autocompleteTableView.dataSource = self
autocompleteTableView.scrollEnabled = true
autocompleteTableView.hidden = true
// Register cell
autocompleteTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "AutoCompleteRowIdentifier")
}
I have a tableView (not static cells) with two sections
A bar section and a club section( and each has several cells). I want that every cell from the same section goes to the same viewcontroller.
I can only acces the first one, never the last one. Even de cells from the second section go to the first viewcontroller.
Can someone see my mistake?
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if section == 0 {
return areas.bars.count
} else {
return areas.clubs.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mainIdentifier", forIndexPath: indexPath)
if indexPath.section == 0 {
let bars = areas.bars
let bar = bars[indexPath.row]
cell.textLabel?.text = bar.name
return cell
} else {
let clubs = areas.clubs
let club = clubs[indexPath.row]
cell.textLabel?.text = club.name
return cell
}
}
the segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "barsandclubsIdentifier"{
let selectedIndex = self.tableView.indexPathForSelectedRow!
let selectedBar = self.areas.bars[selectedIndex.row]
let detailBarsAndClubsViewController = segue.destinationViewController as! DetailBarOrClubViewController
detailBarsAndClubsViewController.bars = selectedBar
}
else {
let selectedIndex = self.tableView.indexPathForSelectedRow!
let selectedClub = self.areas.clubs[selectedIndex.row]
let detailBarsAndClubsTwoViewController = segue.destinationViewController as! DetailBarOrClubTwoViewController
detailBarsAndClubsTwoViewController.clubs = selectedClub
}
Each prototype cell can only segue to a single viewController. If you have 2 different destination viewControllers, you need 2 prototype cells: 1 for bars and 1 for clubs. Give them each a unique identifier such as "barCell" and "clubCell".
Then in cellForRowAtIndexPath, dequeue the proper cell:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellID = ["barCell", "clubCell"][indexPath.section]
let cell = tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath: indexPath)
Then you can wire each prototype cell to go to the appropriate viewController. Give each of these two segues a unique identifier such as "barSegue" and "clubSegue" and then you can use those in prepareForSegue to configure the destination viewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "barSegue"{
let selectedIndex = self.tableView.indexPathForSelectedRow!
let selectedBar = self.areas.bars[selectedIndex.row]
let detailBarViewController = segue.destinationViewController as! DetailBarViewController
detailBarsViewController.bars = selectedBar
}
else if segue.identifier = "clubSegue" {
let selectedIndex = self.tableView.indexPathForSelectedRow!
let selectedClub = self.areas.clubs[selectedIndex.row]
let detailClubViewController = segue.destinationViewController as! DetailClubViewController
detailClubsViewController.clubs = selectedClub
}
}