UITableView editing - select cell without cell highlighting - ios

I have images in my tableView cells, so I have set the cell selectionStyle to None, in order to avoid the cells highlighting when they're selected.
I'm now trying to implement editing into the tableView, allowing users to select multiple cells, filling in the checkmark cirle on the left of the cells. However, this doesn't seem to work with a selectionStyle of None - the circle just remains unfilled.
Is there any way to solve this?
Thanks?

If you can't select the cells directly you can place a uibutton in the cell and recognize in which cell the button that was tapped was.To do that you can set the button tag to equal the indexPath.row inside the cellForRowAtIndexPath method.
The code below prints the correct row number. Hope this helps.
class MyTableViewCell: UITableViewCell {
#IBOutlet weak var onButton: UIButton!
}
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
func buttonClicked(sender:UIButton) {
let buttonRow = sender.tag
print(buttonRow)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! MyTableViewCell
cell.onButton.tag = indexPath.row
cell.onButton.addTarget(self, action: #selector(ViewController.buttonClicked(sender:)), for: .touchUpInside)
return cell
}}

Related

Manage tableview cell after reloading cell from tableview, Data in textfield is not getting clear

initial point App start screenshot
the second screenshot when I add new cell
after adding third and fourth cell
after fifth it reload the cell again
UITableviewcell containing text field. Each cell text field should contain different data. when user enter.
My issue is when table view load with a first cell(Individual 1). when I add next cell(Individual 2) and continue adding cell(Individual 3, Individual 4) as shown in the screenshot. when I add the cell(Individual 5) the cell(Individual 5) with text field reload the same data of a cell of (Individual 1). The cell of the individual 5 text field should be empty.
But I cannot manage the cell and clear the text field when they reload the cell?
I am new in swift...
Please HELP!!
Thx in advances...
class ViewController:UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var addmore: UIButton!
var ar = ["Individual 1"]
#IBOutlet weak var tableview: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ar.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "cell") as! TableTVC
cell.indivuallbl.text! = ar[indexPath.row ]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 240.5
}
#IBAction func deleterow(_ sender: Any) {
let point = (sender as AnyObject).convert(CGPoint.zero, to: tableview)
guard let indexPath = tableview.indexPathForRow(at: point) else {
return
}
ar.remove(at: indexPath.row)
print(ar.count)
}
override func viewDidLoad() {
super.viewDidLoad()
NSLog("a", 1)
addmore.layer.cornerRadius = 5
}
#IBAction func addmore(_ sender: Any) {
ar.insert("Individual \(ar.count + 1 )", at: ar.count)
print(ar.count)
let myIndexPath = IndexPath(row: ar.count-1 , section: 0)
tableview.insertRows(at: [myIndexPath], with: .bottom)
}
TableView Cell reuse itself. Everytime it reused, prepareForReuse method is called. Override this method of your cell. Set values to nil.
Refer this link:- https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse
override func prepareForReuse() {
// Clean up all values
}

UITableView Custom Cell button selects other buttons out of the main view?

On my custom tableviewcell I have a button which the user can press which toggles between selected and unselected. This is just a simple UIButton, this button is contained with my customtableviewcell as an outlet.
import UIKit
class CustomCellAssessment: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var dateTaken: UILabel!
#IBOutlet weak var id: UILabel!
#IBOutlet weak var score: UILabel!
#IBOutlet weak var button: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func selectButton(_ sender: UIButton) {
if sender.isSelected{
sender.isSelected = false
}else{
sender.isSelected = true
}
}
}
The strange thing is, when I press a button on say the first cell it then selects a button 8 cells down on another cell (out of the view) in the same tableview. Each cell has its own button but it is as if using dequeReusableCell is causing the system to behave this way. Why is it doing this and is it to do with the way that UIbuttons work on tableviewcells?
Thanks
Each cell has its own button but it is as if using dequeReusableCell is causing the system to behave this way.
Wrong. UITableViewCells are reusable, so if your tableView has 8 cells visible, when loading the 9th, the cell nr 1 will be reused.
Solution: You need to keep track of the state of your cells. When the method cellForRowAtIndexPath is called, you need to configure the cell from scratch.
You could have in your ViewController an small array containing the state of the cells:
var cellsState: [CellState]
and store there the selected state for each indexPath. Then in the cellForRowAtIndexPath, you configure the cell with the state.
cell.selected = self.cellsState[indexPath.row].selected
So, an overview of I would do is:
1 - On the cellForRowAtIndexPath, I would set
cell.button.tag = indexPath.row
cell.selected = cellsState[indexPath.row].selected
2 - Move the IBAction to your ViewController or TableViewController
3 - When the click method is called, update the selected state of the cell
self.cellsState[sender.tag].selected = true
Remember to always configure the whole cell at cellForRowAtIndexPath
Edit:
import UIKit
struct CellState {
var selected:Bool
init(){
selected = false
}
}
class MyCell: UITableViewCell {
#IBOutlet weak var button: UIButton!
override func awakeFromNib() {
self.button.setTitleColor(.red, for: .selected)
self.button.setTitleColor(.black, for: .normal)
}
}
class ViewController: UIViewController, UITableViewDataSource {
var cellsState:[CellState] = []
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//Add state for 5 cells.
for _ in 0...5 {
self.cellsState.append(CellState())
}
}
#IBAction func didClick(_ sender: UIButton) {
self.cellsState[sender.tag].selected = true
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellsState.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MyCell
cell.button.isSelected = self.cellsState[indexPath.row].selected
cell.button.tag = indexPath.row
return cell
}
}
When you tap the button, you're setting the selected state of the button. When the cell gets reused, the button is still selected - you're not doing anything to reset or update that state.
If button selection is separate to table cell selection, then you'll need to keep track of the index path(s) of the selected buttons as part of your data model and then update the selected state of the button in tableView(_: cellForRowAt:).
A table view will only create as many cells as it needs to display a screen-and-a-bits worth of information. After that, cells are reused. If a cell scrolls off the top of the screen, the table view puts it in a reuse queue, then when it needs to display a new row at the bottom as you scroll, it pulls that out of the queue and gives it to you in tableView(_: cellForRowAt:).
The cell you get here will be exactly the same as the one you used 8 or so rows earlier, and it's up to you to configure it completely. You can do that in cellForRow, and you also have an opportunity in the cell itself by implementing prepareForReuse, which is called just before the cell is dequeued.
In your tableView(_: cellForRowAt:) take action for button click and add target
cell.button.addTarget(self, action: #selector(self.selectedButton), for: .touchUpInside)
At the target method use below lines to get indexPath
func selectedButton(sender: UIButton){
let hitPoint: CGPoint = sender.convert(CGPoint.zero, to: self.tableView)
let indexPath: NSIndexPath = self.tableView.indexPathForRow(at: hitPoint)! as NSIndexPath
}
Then do your stuff by using that indexPath.
Actually your method can not find in which indexPath button is clicked that's why not working your desired button.
One way to approach your problem is as follow
1. First create a protocol to know when button is clicked
protocol MyCellDelegate: class {
func cellButtonClicked(_ indexPath: IndexPath)
}
2. Now in your cell class, you could do something like following
class MyCell: UITableViewCell {
var indexPath: IndexPath?
weak var cellButtonDelegate: MyCellDelegate?
func configureCell(with value: String, atIndexPath indexPath: IndexPath, selected: [IndexPath]) {
self.indexPath = indexPath //set the indexPath
self.textLabel?.text = value
if selected.contains(indexPath) {
//this one is selected so do the stuff
//here we will chnage only the background color
backgroundColor = .red
self.textLabel?.textColor = .white
} else {
//unselected
backgroundColor = .white
self.textLabel?.textColor = .red
}
}
#IBAction func buttonClicked(_ sender: UIButton) {
guard let delegate = cellButtonDelegate, let indexPath = indexPath else { return }
delegate.cellButtonClicked(indexPath)
}
}
3. Now in your controller. I'm using UItableViewController here
class TheTableViewController: UITableViewController, MyCellDelegate {
let cellData = ["cell1","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4"]
var selectedIndexpaths = [IndexPath]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellData.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 55.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
cell.cellButtonDelegate = self
cell.configureCell(with: cellData[indexPath.row], atIndexPath: indexPath, selected: selectedIndexpaths)
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30.0
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! MyCell
cell.buttonClicked(UIButton())
}
func cellButtonClicked(_ indexPath: IndexPath) {
if selectedIndexpaths.contains(indexPath) {
//this means cell has already selected state
//now we will toggle the state here from selected to unselected by removing indexPath
if let index = selectedIndexpaths.index(of: indexPath) {
selectedIndexpaths.remove(at: index)
}
} else {
//this is new selection so add it
selectedIndexpaths.append(indexPath)
}
tableView.reloadData()
}
}

Trying to change the height of cell contains pickerview when tapping it

I am trying to make cell containing UIPickerView expand when tapped to show more area from my PickerView by changing the cell's height and go back to normal size after the picker selection is done.
When i am tapping the cell only the PickerView inside it is tapped .. so i was unable to use HeightForRow to change the cell height.Can anyone can help !
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (indexPath == [0,0])
{
return 150
}else{
return 70
}}
If you set picker.userInteractionEnabled = false, the tap event will be sent to the cell. You would then need to reload the table at that index path (to resize the cell), and re-enable the picker.
You can try to use delegate
protocol HeightManager{
func changeHeight(TableCustomCell)
}
class TableCustomCell: UITableViewCell {
var delegate: HeightManager?
#IBAction func expandCollapseClicked(_ sender: UIButton) {
self.delegate?.changeHeight(sender:self)
}
}
in the VC
class viewController: UIViewController,HeightManager{
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = areaSettTable.dequeueReusableCell(withIdentifier:CellIdentifier1) as! TableCustomCell
cell.delegate = self
return cell
}
func changeHeight(sender:TableCustomCell) {
// change height here in say array of heights
self.tableView.reloadData()
}
}

iOS Swift - TableView rows are blank

I am new to iOS dev and basically I'm trying to populate a TableView with String values from an array.
However when I run the app, blank rows show up and no text values are shown. Have I coded this correctly?
import UIKit
class SelectIssueController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var issuesTableView: UITableView!
var issues = [Issue]()
override func viewDidLoad() {
super.viewDidLoad()
self.issues = ["Test1", "Test2", "Test3"]
self.issuesTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return UIStatusBarStyle.lightContent
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.issues.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.issuesTableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = issues[indexPath.row]
//Even if I manually set a value, the rows are still blank
//cell.textLabel?.text = "Hello World"
return cell
}
}
You can set Table view data source and delegate in two ways.
1. Click Cntrl+drag from tableView to view controller. See below figure
Create the outlet of your tableView and assign its datasource and delegate in ViewDidLoad.
In your example you already have an outlet to issuesTableView, so you would write:
issuesTableView.dataSource = self
issuesTableView.delegate = self
Thanks:)

iOS - TapRecogniser in custom TableViewCell not working properly

I am using Xcode 7 Beta, Swift 2
I have a table view with a custom tableViewCell. In the custom cell there is a UIImageView and Label. I have defined a testCell class for this tableViewCell as well. On the image (within the table) I have added UITapRecogniser. I have also enabled User Interaction
Issue: Currently I have 3 rows in the table. When I click on images on first 2 rows. Nothing happens. When I click on the image in the last row - the action prints "DEF" on the console. This has got nothing to with number of rows - problem persists even after changing to 4, 5 or anything else. Basically only the image in the last row gets tapped. Not sure why?? Below is the code:
//Defining custom class for the TableViewCell
class testCell : UITableViewCell{
#IBOutlet weak var testLabel: UILabel!
#IBOutlet weak var testImage: UIImageView!
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! testCell
cell.testLabel?.text = "ABC"
cell.testImage?.image = UIImage(named: "Santa")
return cell
}
#IBOutlet weak var tableView: UITableView!
//TapGestureRecogniser Function
#IBAction func imageTap(sender: AnyObject) {
print("DEF")
}
move the add gesture recognizer call from testCell to cellforrowatindexpath.
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! testCell
cell.testLabel?.text = "ABC"
cell.testImage?.image = UIImage(named: "Santa")
let cellTapRecognizer = UITapGestureRecognizer(target: self, action:Selector("imageTap:"))
cellTapRecognizer.cancelsTouchesInView = false
cell.testImage?.addGestureRecognizer(cellTapRecognizer)

Resources