In my app I have custom UITableViewCell, and I have UIStepper and UILabel in the custom cell. I don't know how to check which stepper was clicked. So is it a way to know from which cell stepper was clicked? I use swift 3.
I tried this
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let data = ["111111", "2222222","3333333"]
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return(data.count)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.lb1.text = data[indexPath.row]
cell.stepper.tag = indexPath.row
cell.stepper.addTarget(self, action: #selector(stepperA(sender:)), for: .valueChanged)
return (cell)
}
func stepperA (sender: UIStepper){
print("stepper \(sender.tag) clicked. Its value \(sender.value)")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can use tags. Here is an example cellForRowAt and your stepper action function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: StepperTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! StepperTableViewCell
//stepper is your UIStepper reference from StepperTableViewCell
cell.stepper.tag = indexPath.row
cell.stepper.addTarget(self, action: #selector(stepperAction(sender:)), for: .valueChanged)
return cell
}
func stepperAction(sender: UIStepper) {
print("Stepper \(sender.tag) clicked. Its value \(sender.value)")
}
And Its output
Stepper 0 clicked. Its value 1.0
Stepper 1 clicked. Its value 1.0
Stepper 0 clicked. Its value 2.0
Stepper 0 clicked. Its value 3.0
Stepper 3 clicked. Its value 1.0
Related
I created a table view with a custom prototype cell but I need to shape the borders, this is the image I have now
the one i get when i run the app
this is the prototype cell
please note that I created a new class for the tableviewcell where I added a textfield to be changed from a list
I want to set the corners radius
i tried to add this code,
layer.cornerRadius = 10
and
layer.masksToBounds = true
in the user defined runtime attributes like I did before for a button but it doesn't work
Here is the code:
import UIKit
class ListOffersViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let profil = ["Eric","Eric","Eric","Eric","Eric","Eric"]
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return profil.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ListOffersViewControllerTableViewCell
cell.profilName.text = profil[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Be attentive when you work with UITableViewCell. UI features you mind make with contentView.
Here is example.
class ViewController: UITableViewController {
let identifier = "roundedCell"
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: identifier)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = "\(indexPath)"
return cell
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = .red
cell.contentView.backgroundColor = .blue
cell.contentView.layer.cornerRadius = 10.0
}
}
Try adding a UIView on the cell and set the constraints so that it is the same size as the cell. Put all your design objects inside that view. Connect that view to your cell file, then add the corner radius to that view. Make sure you set the cell view background to transparent, and add colour to the new UIView.
My tableview looks like this
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 200
}
And my tableviewcell looks like this
class Cell: UITableViewCell {
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
}
}
When I change switch state on any cell and scroll. The switch for another cell periodically have state changed on scroll for other cells. Please help
You need to have data array with state for every switch and in your didSelect method change data model for switch then in cellForRow at get switch state from array and your viewController need to be SwitchControlDelegate
class UIViewController:SwitchControlDelegate{
var array = [Bool](count: 200, repeatedValue:false)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell
cell.switchControl.isOn = array[indexPath.row]
cell.switchDelegate = self
cell.index = indexPath.row
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 200
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
array[indexPath.row] = !array[indexPath.row]
}
func switchChangeStateWithIndex(index:Int){
array[index] = !array[index]
}
This will change switch state when you click on cell , if you need to change state when change switch control you will need delegate to update data model in viewController
In your cell file:
protocol SwitchControlDelegate: class {
func switchChangeStateWithIndex(index:Int)
}
class Cell: UITableViewCell {
var index:Int = 0
weak var switchDelegate: SwitchControlDelegate?
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 valueChanged(_ sender: AnyObject) {
switchDelegate?.switchChangeStateWithIndex(index:index)
}
}
You need to match action value change from your switch control with this function valueChanged , so every time when you change switch state cell need to call func value Changeed
Handle your switch control properly for each cell in,
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
so that when cell is dequeue, it handles each cell's switchControl properly.
Solution:
When you change state of switch control for cell, save that indexPath somewhere so that when you iterate through this indexPath in tableview cellForRowAt indexPath you set that state of switch again else set default state
I've managed to create cells and have them check select and deselect. How do I get the string names of the cells and how do I keep them checked or unchecked upon button click. Say, for example, if I want to get only the checked cells and saved them to a database upon clicking the button and next time I open the tableview they should be selected/deselected.
import UIKit
class CellsViewController: UITableViewController {
// Creating cells with code
let activities = ["Jumping", "History", "Reading", "Football", "Nightlife", "Hiking", "Spa"]
// Function to figure out how many rows we need depending on the lenght of the list
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return activities.count
}
// returns the cell name and puts it in the table view controller
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = activities[indexPath.row]
return cell
}
// checks and unchecks the given cell based on user click
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark{
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
}else{
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
}
#IBAction func saveButton(_ sender: Any) {
// Retrieve the checked cells and do something
// With them once the button is clicked
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// hi , give tag for that button , by using that tag u need to maintatin selected data in your array of table datasource
let activities = [["name": "Jumping", "isSelected": "NO"], ....]
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = activities[indexPath.row]["name"]
cell.btnSelect.tag = indexPath.row
if activities[indexPath.row]["name"] as String == "Yes" {
cell.btnSelect.isSelected = true
} else {
cell.btnSelect.isSelected = false
}
return cell
}
#IBAction func saveButton(_ sender: Any) {
// Retrieve the checked cells and do something
// With them once the button is clicked
saveButton.isSelected = !saveButton.isSelected
let dicdetails = activities[sender.tag]
if saveButton.isSelected {
dicdetails["isSelected"] = "YES"
} else {
dicdetails["isSelected"] = "No"
}
activities[sender.tag] = dicdetails
}
I am having a problem trying to show an array of images on each cell, for a tableview.
I have a separate TableViewCell Swift file where I have a UIImage on the cell linked up. The outlet is named: CellVenueImage
For some reason when I try to implement the image on my TableView view controller, I get an error that says: Value of type 'TableViewCell' has no member 'CellVenueImage'
Here is the line in which that happens:
cell.CellVenueImage.image = imagename
Using Swift 3.
Here is the code for the TableView:
import UIKit
class VenueTableViewController: UITableViewController {
let VenueImageList = ["1970s.png","1980s.png","1990s.png"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return VenueImageList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "VenueCell", for: indexPath) as! TableViewCell
let imagename = UIImage(named: VenueImageList[indexPath.row])
cell.CellVenueImage.image = imagename
return cell
}
TableViewCell code:
import UIKit
class VenuesTableViewCell: UITableViewCell {
#IBOutlet weak var CellVenueImage: UIImageView!
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
}
The mistake is, that you're not using your created TableViewCell Subclass, you are using a regular UITableViewCell.
let cell = tableView.dequeueReusableCell(withIdentifier: "VenueCell", for: indexPath) as! TableViewCell
You need to cast it as your UITableViewCell subclass.
If it is called "VenuesTableViewCell", for example: class VenuesTableViewCell: UITableViewCell {, then cast it as VenuesTableViewCell.
let cell = tableView.dequeueReusableCell(withIdentifier: "VenueCell", for: indexPath) as! VenuesTableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "VenueCell", for: indexPath) as! VenuesTableViewCell
I have a static table in a TableViewController. Whenever I select a row, it fills the entire cell with a grey color. It does this for every row I tap. If I use:
cell.selectionStyle = .none
It will make the cell fill with white instead.
Tableview Attributes Inspector:
TableViewCell Attributes Inspector:
TableViewController:
import UIKit
class OptionTableViewController: UITableViewController {
#IBOutlet var optionsTable: UITableView!
let defaults = UserDefaults.standard
let numberOfRows = [7,2]
let cellIdentifier = "OptionCells"
override func viewDidLoad() {
super.viewDidLoad()
optionsTable.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that con be recreated.
}
override func numberOfSections(in 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
var rows = 0
if(section < numberOfRows.count){
rows = numberOfRows[section]
}
return rows
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.selectionStyle = .none
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
cell.textLabel?.text = optionSelections[indexPath.row]
return cell
}
}
I believe I have everything setup correctly. Why does it fill in the cells when I tap them?
Update:
I updated the code to show what I currently have.
Update 2:
I've included a couple of pictures to show what the table looks like before and after tapping every other cell.
Update 3:
I was dequeuing cells to change the accessory type to checkmark.
Before:
After:
As discussed in comments, I think the problem is a symptom of dequeuing cells in the didSelectRow(at:) method:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
}
You should instead use
let cell = tableView.cellForRow(at: indexPath)
That gets the cell that is currently at the given indexPath (be aware that it may return nil if that indexPath has been scrolled off or was never on screen). Dequeuing gets an unused cell to go at the given indexPath - which (I think) then sits in front of the existing cell - hence the weird behaviour.
You need to set selectionStyle BEFORE the selection happens.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.selectionStyle = .none
cell.selectedBackgroundView = UIView() // optional
cell.selectedBackgroundView?.backgroundColor = UIColor.white // optional
}