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