How to make clickable table view and method didSelectRowAt - ios

I have a drop-down list that I implemented using table view:
When choosing another floor, information in the center should be substituted.
I have extension:
extension DDList: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (Manager.shared()?.location.floor.count)!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = Manager.shared()?.location.floor[indexPath.row].name
cell.textLabel?.textAlignment = .center
cell.textLabel?.textColor = .white
cell.textLabel?.font = font
cell.backgroundColor = UIColor.black
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let indexPath = Manager.shared()?.location.floor[indexPath.row].name
let currentCell = tableView.cellForRow(at: indexPath) as UITableViewCell
let currentItem = currentCell.textLabel!.text
}
I can’t make the functionality of selecting an item from a list in a didSelectRowAt method, please tell me how to do it? So that the selected floor is saved from the top to the middle where at the moment (1-st floor)

I would prefer to do that:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let nameOfCurrentItem = Manager.shared()?.location.floor[indexPath.row].name
//if you use a navigation bar
self.navigationBar.topItem?.title = nameOfCurrentItem
//if you use a label
myLabel.text = nameOfCurrentItem
}
If you need an animation:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let nameOfCurrentItem = Manager.shared()?.location.floor[indexPath.row].name
if let currentCell = tableView.cellForRow(at: indexPath){
UIView.animate(withDuration: 0.3, animations: {
currentCell.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
//or any other animation
//currentCell.alpha = 0.5
}) { (_) in
UIView.animate(withDuration: 0.3, animations: {
currentCell.transform = CGAffineTransform.identity
//or any other animation
//currentCell.alpha = 1.0
}) { (_) in
//if you use a navigation bar
self.navigationBar.topItem?.title = nameOfCurrentItem
//if you use a label
self.myLabel.text = nameOfCurrentItem
}
}
}
}
Also ensure that your tableViewCell and tableView itself are able to be selected in the attributes inspector:
TableView selection settings
TableViewCell selection settings

Related

UITableViewCell 3 Time Selected Change Background Color on Multiple Selection

I have 5 rows. Background color will change when 3 or more is selected.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let backgroundView = UIView()
backgroundView.backgroundColor = YOUR_COLOR_HERE
cell.selectedBackgroundView = backgroundView
return cell
}
These code change bacground color. But I want the background color to change when 3 or more is selected.
How can I do that?
First of all you should add configuration for both states, whether tableviewCell meets the isTapsEnough condition or not.
var numberOfTaps: Int = 0
var isTapsEnough: Bool { retrun numberOfTaps >= 3 }
func tap() {
self.numberOfTaps += 1
if self.isTapsEnough {
self.tableView.reloadData()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.contentView.backgroundColor = self.isTapsEnough ? .yellow : .clear
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) -> UITableViewCell {
self.tap()
}
you can use this
var numberTaps = 0
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//code cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if numberTaps == 3
{
cell.backgroundColor = .red
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) -> UITableViewCell {
numberTaps += 1
if numberTaps == 3
{
tableView.reloadData()
}
}
You can try with this example, although code syntax may be wrong.
var indexPaths: [IndexPath] = [IndexPath]()
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if tableView.indexPathsForSelectedRows?.contains(indexPath) ?? false {
tableView.deselectRow(at: indexPath, animated: true)
return nil
}
indexPaths.append(indexPath)
return indexPath
}
func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
for (index, value) in indexPaths.enumerated() {
if value == indexPath {
indexPaths.remove(at: index)
}
}
return nil
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//code cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if indexPaths.count >= 3
{
cell.backgroundColor = .red
}
return cell
}
Best way to make adjustments in the background color, etc is in willDisplayCell and observe indexPathsForSelectedRows:
(disclaimer: typed in browser, not tested in Xcode)
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if tableView.indexPathsForSelectedRows.count >= 3 && tableView.indexPathsForSelectedRows.contains(indexPath) {
cell.backgroundColor = .red // or change the backgroundView color
}
else {
cell.backgroundColor = .clear // or whatever color you want
}
}
This will help you to start
var SelectedIndexpath = [IndexPath]()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if SelectedIndexpath.contains(indexPath){
SelectedIndexpath.remove(at: SelectedIndexpath.index(of: indexPath)!)
}else{
SelectedIndexpath.append(indexPath)
}
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if SelectedIndexpath.count >= 3 && SelectedIndexpath.contains(indexPath){
cell.backgroundColor = .red
}else{
cell.backgroundColor = .white
}
cell.accessoryType = SelectedIndexpath.contains(indexPath) ? .checkmark : .none
cell.textLabel?.text = "\(indexPath.row)"
return cell
}

present UITableViewController the door cell TableViewController?

I want SelectRow open tableview without storyboard ??
tableview without storyboard
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 3 {
let main = UITableViewController()
let color = UIColor.yellow
main.view.backgroundColor = color
self.present(main, animated: true)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let name = twoDimensionalArray[indexPath.section][indexPath.row]
return cell
}
You shouldn't nest the functions
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 3 {
let main = UITableViewController()
let color = UIColor.yellow
main.view.backgroundColor = color
self.present(main, animated: true)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let name = twoDimensionalArray[indexPath.section][indexPath.row]
// use name here
return cell
}

Expanded and Swipe-able cell in TableView

I have TableView, where users can click and expand each cell (UI: click). This is the code for that (also I created .xib file to layout this cell):
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
var selectedIndex: IndexPath?
var isExpended = false
func didExpandCell() {
self.isExpended = !isExpended
self.tableView.reloadRows(at: [selectedIndex!], with: .automatic)
}
#IBOutlet weak var tableView: UITableView!
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "wordCell", for: indexPath) as! CellController
if searchController.isActive {
cell.word.text = filtered[indexPath.row].word
cell.translation.text = filtered[indexPath.row].translation
cell.date.text = filtered[indexPath.row].fullDate
cell.exOne.text = filtered[indexPath.row].exOne
cell.exTwo.text = filtered[indexPath.row].exTwo
} else {
cell.word.text = words[indexPath.row].word
cell.translation.text = words[indexPath.row].translation
cell.date.text = words[indexPath.row].fullDate
cell.exOne.text = words[indexPath.row].exOne
cell.exTwo.text = words[indexPath.row].exTwo
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath
self.didExpandCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if isExpended && self.selectedIndex == indexPath {
return 180
}
return 70
}
}
Also, all Cells are swipe-able. This is the code:
func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
let edit = UITableViewRowAction(style: .normal, title: "Edit") { action, index in
print("Edit")
}
edit.backgroundColor = .blue
let delete = UITableViewRowAction(style: .normal, title: "Delete") { action, index in
print("Delete")
}
delete.backgroundColor = .red
return [delete, edit]
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
The problem:
When I swipe Cell, it always expends in a half, this is my UI after swiping: click. Is it possible not to expand Cell if I swipe them?
Excuse me, but the problem was that I haven't set constraints for expanded version of the cell. That's why this labels were moving with swipe menu. Now it works.
Thank you for all your replies!

CheckBox on tableview duplicating, Swift, iOS

I have a tableView that when selected changes an image from one to another. This all works fine but when I select a tableCell it changes the image, but when I scroll it has also changed the image of another cell that I didn't select.
Below is my code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturesCell") as! FeaturesCell
cell.featuresLabel.text = self.items[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
pickedFeatures.append(items[indexPath.row])
let cell = tableView.cellForRow(at: indexPath) as! FeaturesCell
cell.checkImage.image = #imageLiteral(resourceName: "tick-inside-circle")
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
pickedFeatures.remove(at: pickedFeatures.index(of: items[indexPath.row])!)
let cell = tableView.cellForRow(at: indexPath) as! FeaturesCell
cell.checkImage.image = #imageLiteral(resourceName: "No-tick-inside-circle")
}
If I use detqueureusable cell in the did select function then it just doesn't change the picture at all when selected.
You can use tableView.dequeueReusableCell(_), The problem is, you didn't maintain the status of the selected cells.
Example :
class viewController: UIVieWController, UITableViewDelegate, UITableViewDataSource {
var selectedCellList = [IndexPath]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FeaturesCell") as! FeaturesCell
cell.featuresLabel.text = self.items[indexPath.row]
if let _ = selectedCellList.index(of: indexPath) {
// Cell selected, update check box image with tick mark
cell.checkImage.image = #imageLiteral(resourceName: "tick-inside-circle")
} else {
// Cell note selected, update check box image without tick mark
cell.checkImage.image = #imageLiteral(resourceName: "No-tick-inside-circle")
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
pickedFeatures.append(items[indexPath.row])
if let index = selectedCellList.index(of: indexPath) {
selectedCellList.remove(at: index)
} else {
selectedCellList.append(indexPath)
}
tableView .reloadRows(at: [indexPath], with: .automatic)
}
}

Expanding tableview cell data being overwritten when selected

I have a transaction tableview with different types of expenses that expands to show more detail when selected.
However the detail appears to be overwritten when this happens. I can see it flash and sometimes it does get populated. The textfields get populated correctly. I have been trying to debug this for a while, but not sure how to work around this problem.
Here is my current implementation:
// MARK: Tableview
extension TransactionViewController: UITableViewDelegate, UITableViewDataSource {
// MARK: - Table View
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardTableViewCell
cell.delegate = self
var isDetailHidden = true
if indexPath.row == rowSelected {
isDetailHidden = false
}
let transaction = transactionList[indexPath.row]
cell.configureCell(transaction: transaction, isDetailHidden: isDetailHidden)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return transactionList.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == rowSelected {
// don't refresh and set again.
return
}
rowSelected = indexPath.row
transactionBeingEdited = transactionList[indexPath.row]
transactionTableView.setContentOffset(CGPoint(x: 0, y: rowSelected! * 76), animated: true)
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardTableViewCell
cell.delegate = self
cell.configureDetailCell()
transactionTableView.reloadData()
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let transaction = transactionList[indexPath.row]
coreDataManager.deleteTransaction(transaction: transaction)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row != rowSelected {
return 76.5
} else {
return 323
}
}
The variables in the detail section are dropdown boxes using a library. I've configured it in the UITableViewCell class. Setting up the dropdown methods occurs in the awakefromnib method.
private func setupBillDropDown() {
billDropDown.anchorView = bill
billDropDown.bottomOffset = CGPoint(x: 0, y: bill.bounds.height)
billDropDown.dataSource = TransactionType.list
// Action triggered on selection
billDropDown.selectionAction = { [unowned self] (index, item) in
self.bill.setTitle(item, for: .normal)
self.bill.setTitleColor(UIColor.white, for: .normal)
// Update transaction
if let transactionBeingEdited = self.delegate?.transactionBeingEdited {
transactionBeingEdited.type = item
self.coreDataManager.saveToCoreData()
self.coreDataManager.nc.post(name: .transactionBeingEdited, object: nil, userInfo: nil)
}
}
}
Thanks in advance.
I think in func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) you are overwriting the configured cell by loading the table. Try this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == rowSelected {
// don't refresh and set again.
return
}
rowSelected = indexPath.row
transactionBeingEdited = transactionList[indexPath.row]
transactionTableView.setContentOffset(CGPoint(x: 0, y: rowSelected! * 76), animated: true)
//let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardTableViewCell
let cell = tableView.cellForRow(at: indexPath)
cell.configureDetailCell()
tableView.reloadRows(at: [indexPath], with: .none)
}
I figured out the issue after spending literally hours on it... It's because I was updating the buttons title using
bill.titleLabel!.text = transaction.type ?? "Select Bill"
insteaad of
bill.setTitle(transaction.type ?? "Select Bill", for: .normal)

Resources