radio buttons in a tableview cells swift - ios

Currently I am trying to make a store-like view that shows multiple different listing (spaceships) and you can only select one at a time. It would be for a game where you can select your different spaceships. I am sing a UITableView with a UITableViewCell Xib file. I have only one table cell Xib file to format all of the different listings. The style of the Select button is suppose to be like a Radio Button.
The difficulty I am having is that when I click one button, it makes all the buttons say "Selected."
This is the code that I have:
TableViewController:
import UIKit
struct CellData {
var image: UIImage?
var message: String?
var id: Int?
}
var array = [String]()
var buttonArray = [ShopButton]()
class ViewController: UITableViewController {
var data = [CellData]()
override func viewDidLoad() {
super.viewDidLoad()
data = [CellData.init(image: #imageLiteral(resourceName: "ship_0"), message: "Red Ship", id: 0), CellData.init(image: #imageLiteral(resourceName: "ship_1"), message: "Blue Ship", id: 1), CellData.init(image: #imageLiteral(resourceName: "ship_3"), message: "Yellow Ship", id: 2)]
array = ["Select", "Select", "Select"]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = Bundle.main.loadNibNamed("TableViewCell", owner: self, options: nil)?.first as! TableViewCell
cell.mainImageView.image = data[indexPath.row].image
cell.mainLabel.text = data[indexPath.row].message
cell.buttonOutlet.setTitle(array[indexPath.row], for: .normal)
cell.buttonOutlet.tag = data[indexPath.row].id!
buttonArray.append(cell.buttonOutlet)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
}
TableViewCell
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var mainImageView: UIImageView!
#IBOutlet weak var mainLabel: UILabel!
#IBOutlet weak var buttonOutlet: ShopButton!
#IBAction func button(_ sender: ShopButton) {
buttonOutlet.makeSelected()
}
override func awakeFromNib() {
super.awakeFromNib()
}
My SubClass for the UIButton:
import UIKit
class ShopButton: UIButton {
var buttonID = Int()
func makeSelected() {
switch self.buttonID {
case 0:
array = ["Selected", "Select", "Select"]
buttonTitle()
print("Ship: Red Ship")
case 1:
array = ["Select", "Selected", "Select"]
buttonTitle()
print("Ship: Blue Ship")
case 2:
array = ["Select", "Select", "Selected"]
buttonTitle()
print("Ship: Yellow Ship")
default:
print("Error: Default Initiated")
}
}
func buttonTitle() {
for button:ShopButton in buttonArray {
button.setTitle(array[button.buttonID], for: .normal)
}
}
override func awakeFromNib() {
}
}
I realize this might not be the best approach to making this shop setup so if anyone has an answer to how to fix this or a different way that would be much better than what I have currently done, it would be much appreciated. Thanks.

You can possibly use this logic in didSelectRowAt in table view like:
You can make the tag of button equivalent to the indexpath.row of tableview
for (button in buttons) {
button.isSelected = false;
}
if button.tag == indexpath.row{ //Here sender.tag would be your indexPath.row
button.isSelected = true;
button.setImage(#imageLiteral(resourceName: "ic_Radio_filled"), for: .normal)
}else{
button.isSelected = false;
button.setImage(#imageLiteral(resourceName: "ic_Radio_Empty"), for: .normal)
}
Let me know if it works for you.

Related

In swift, how to manage two buttons in same custom tableview cell?

I am trying to manage two buttons in same custom tableview cell.
Added two buttons named Yes and No. If yes button is selected the No button will be inactive and Yes button became active.
Here is the image what I need
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell") as! TableViewCell
cell.yesButton.tag = 101
cell.noButton.tag = 102
cell.yesButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
cell.noButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
#objc func buttonClicked(sender: AnyObject) {
let buttonPosition = (sender as AnyObject).convert(CGPoint.zero, to: tableList)
let indexPath = tableList.indexPathForRow(at: buttonPosition)
if sender.tag == 101 {
if indexPath != nil {
print("Cell indexpath = \(String(describing: indexPath?.row))")
}
}
if sender.tag == 102 {
if indexPath != nil {
print("Cell indexpath = \(String(describing: indexPath?.row))")
}
}
}
Create a model to main the state of yesButton and noButton for each tableViewCell, i.e.
class Model {
var isYesSelected = false
var isNoSelected = false
}
Create a custom UITableViewCell with Outlets of yesButton and noButton.
Create a single #IBAction for both the buttons and handle their UI based on which button is tapped.
Also, use a buttonTapHandler to identify the row in which the button is tapped. It will be called everytime a button is tapped. We'll be setting this when creating the instance of TableViewCell in tableView(_:cellForRowAt:).
class TableViewCell: UITableViewCell {
#IBOutlet weak var yesButton: UIButton!
#IBOutlet weak var noButton: UIButton!
var buttonTapHandler: (()->())?
var model: Model?
override func prepareForReuse() {
super.prepareForReuse()
yesButton.backgroundColor = .gray
noButton.backgroundColor = .gray
}
func configure(with model: Model) {
self.model = model
self.updateUI()
}
#IBAction func onTapButton(_ sender: UIButton) {
model?.isYesSelected = (sender == yesButton)
model?.isNoSelected = !(sender == yesButton)
self.updateUI()
}
func updateUI() {
yesButton.backgroundColor = (model?.isYesSelected ?? false) ? .green : .gray
noButton.backgroundColor = (model?.isNoSelected ?? false) ? .green : .gray
}
}
UITableViewDataSource's tableView(_:cellForRowAt:) method goes like,
let numberOfCells = 10
var models = [Model]()
override func viewDidLoad() {
super.viewDidLoad()
(0..<numberOfCells).forEach { _ in
self.models.append(Model())
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCells
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! TableViewCell
cell.configure(with: models[indexPath.row])
cell.buttonTapHandler = {
print(indexPath.row)
}
return cell
}
To get the totalPoints, count the models with isYesSelected = true, i.e.
let totalPoints = models.reduce(0) { (result, model) -> Int in
if model.isYesSelected {
return result + 1
}
return 0
}
print(totalPoints)
Get that Button using your Tag like below and after that, you can change the value as per you want.
var tmpButton = self.view.viewWithTag(tmpTag) as? UIButton
Simple 3 step process...!!
Define Model Class
Prepare tableView Cell & handle actions
Set up tableView in view controller
Let's start implementation:
1) Define Model Class
In UI, we have a information like question & it's answer (Yes/No). So design model respectively.
//MARK:- Class Declaration -
class Question {
let questionText: String
var answerState: Bool?
init(question: String) {
self.questionText = question
}
}
2. Prepare tableView Cell & handle actions
Create a custom tableView cell with Question Label, Yes Button & No Button. Link that view with respected #IBOutlets & #IBActions.
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var yesButton: UIButton!
#IBOutlet weak var noButton: UIButton!
var question: Question?
var toggle: Bool? {
didSet {
question?.answerState = toggle
//Do buttons operations like...
if let isToggle = toggle {
yesButton.backgroundColor = isToggle ? .green : .gray
noButton.backgroundColor = isToggle ? .gray : .green
} else {
yesButton.backgroundColor = .gray
noButton.backgroundColor = .gray
}
}
}
func prepareView(forQuestion question: Question) {
self.question = question
questionLabel.text = question.questionText
toggle = question.answerState
}
//Yes Button - IBAction Method
#IBAction func yesButtonTapped(_ sender: UIButton) {
toggle = true
}
//No Button - IBAction Method
#IBAction func noButtonTapped(_ sender: UIButton) {
toggle = false
}
}
3. Set up tableView in view controller
class ViewController: UIViewController {
//Prepare questions model array to design our tableView data source
let arrQuestions: [Question] = [Question(question: "Do you speak English?"), Question(question: "Do you live in Chicago?")]
}
//MARK:- UITableView Data Source & Delegate Methods -
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrQuestions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as? TableViewCell else {
return UITableViewCell()
}
tableViewCell.prepareView(forQuestion: arrQuestions[indexPath.row])
return tableViewCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
}
Create basic tableView and configure dataSource functions
Create tableView cell with two buttons
Create cell class with buttons outlets and actions
Result of this code
Enjoy!

Is there a way to get the value from a text filed in a table view cell to use it in another table view cell?

I'm building an iOS e-commerce app which sells shoe products. This question is about the Checkout screen which is a UITableViewController to collect billing information of the user and save it in Firebase.
Below UITableViewController contains two custom UITableView cells. The first cell contains some text fields to get billing information(Email, Card Number, Expiration Date and CVC) from the user, while the second cell below that contains a submit button to save them in Firebase.
My requirement is to get the billing information from the user and save it in Firebase when clicking the Submit button. (Text fields and submit button are in two separate UITableView cells)
Could you please help me with this. Please find below code snippets.
CheckoutViewController.swift
class CheckoutTableViewController: UITableViewController {
// MARK: - Properties
var shoes : [Shoe]! {
didSet {
tableView.reloadData()
}
}
// MARK: - Structs
struct Storyboard {
static let billingInfoCell = "billingInfoCell"
static let submitButtonCell = "submitButtonCell"
}
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.billingInfoCell, for: indexPath) as! BillingInfoTableViewCell // Contains billing information text fields
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: Storyboard.submitButtonCell, for: indexPath) as! SubmitButtonTableViewCell // Contains Submit button
return cell
} else {
return UITableViewCell()
}
}
}
BillingInfoTableViewCell.swift
class BillingInfoTableViewCell: UITableViewCell {
// MARK: - IBOutlets
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var cardNumberTextField: UITextField!
#IBOutlet weak var expirationDataTextField: UITextField!
#IBOutlet weak var securityNumberTextField: UITextField!
}
SubmitButtonTableViewCell.swift
class SubmitButtonTableViewCell: UITableViewCell {
// MARK: - IBActions
#IBAction func submitOrderButtonTapped(_ sender: UIButton) {
print("Submit button tapped!")
}
}
Please follow the below steps.
Make the outlet of UITableView
#IBOutlet weak var tableView: UITableView!
Make static UITableviewCell
lazy var cellBillingInfo = tableView.dequeueReusableCell(withIdentifier: Storyboard.billingInfoCell) as! BillingInfoTableViewCell
lazy var cellSubmit = tableView.dequeueReusableCell(withIdentifier: Storyboard.submitButtonCell) as! SubmitButtonTableViewCell
Add target for submit button as below.
cellSubmit.btnSumit.addTarget(self, action: #selector(submitOrderButtonTapped(_:).tou), for: .touchUpInside)
Define submit button method
#objc func submitOrderButtonTapped(_ sender: UIButton) {
print(cellBillingInfo.emailTextField.text)
print(cellBillingInfo.cardNumberTextField.text)
print(cellBillingInfo.expirationDataTextField.text)
print(cellBillingInfo.securityNumberTextField.text)
}
Final Code:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
// MARK: - Properties
lazy var cellBillingInfo = tableView.dequeueReusableCell(withIdentifier: Storyboard.billingInfoCell) as! BillingInfoTableViewCell
lazy var cellSubmit = tableView.dequeueReusableCell(withIdentifier: Storyboard.submitButtonCell) as! SubmitButtonTableViewCell
var shoes : [Shoe]! {
didSet {
tableView.reloadData()
}
}
// MARK: - Structs
struct Storyboard {
static let billingInfoCell = "billingInfoCell"
static let submitButtonCell = "submitButtonCell"
}
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Data source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
return cellBillingInfo
} else if indexPath.row == 1 {
cellSubmit.btnSumit.addTarget(self, action: #selector(submitOrderButtonTapped(_:).tou), for: .touchUpInside)
return cellSubmit
} else {
return UITableViewCell()
}
}
#objc func submitOrderButtonTapped(_ sender: UIButton) {
print(cellBillingInfo.emailTextField.text)
print(cellBillingInfo.cardNumberTextField.text)
print(cellBillingInfo.expirationDataTextField.text)
print(cellBillingInfo.securityNumberTextField.text)
}
}
class SubmitButtonTableViewCell: UITableViewCell {
#IBOutlet weak var btnSumit: UIButton!
}

Open URL with a button inside a table view cell

I want to include a button in each table cell that opens a URL.
I've created tables (using an array) with images and labels just fine, however I'm confused how to create a button
Here's what I have so far
class ExploreCell: UITableViewCell {
#IBOutlet weak var exploreImageView: UIImageView!
#IBOutlet weak var exploreTitleView: UILabel!
#IBOutlet weak var exploreDescriptionView: UILabel!
#IBOutlet weak var exploreButton: UIButton!
func setExplore(explore: Explore) {
exploreImageView.image = explore.image
exploreTitleView.text = explore.title
exploreDescriptionView.text = explore.description
exploreButton.addTarget(self, action: "connected:", for: .touchUpInside) = explore.button
}
My Class for the array looks like this
class ExploreListScreen: UIViewController {
#IBOutlet weak var tableView: UITableView!
var explores: [Explore] = []
override func viewDidLoad() {
super.viewDidLoad()
explores = createArray ()
tableView.delegate = self
tableView.dataSource = self
}
func createArray() -> [Explore] {
var tempExplores: [Explore] = []
let explore1 = Explore(image: #imageLiteral(resourceName: "test"), title: "Demo", description: "Essential", button: "")
tempExplores.append(explore1)
return tempExplores
}
Finally I have another file which contains the declared variables
class Explore {
var image: UIImage
var title: String
var description: String
var button: UIButton
init(image: UIImage, title: String, description: String, button: UIButton) {
self.image = image
self.title = title
self.description = description
self.button = button
}
Any advice and guidance would be fantastic. Thank-you!
Here's how I usually solve this. Create a delegate for your UITableViewCell subclass, and set the view controller owning the tableView as its delegate. Add methods for the interactions that happens inside the cell.
protocol YourTableViewCellDelegate: class {
func customCellDidPressUrlButton(_ yourTableCell: YourTableViewCell)
}
class YourTableViewCell: UITableViewCell {
weak var delegate: YourTableViewCellDelegate?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let button = UIButton()
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
addSubview(button)
}
required init?(coder _: NSCoder) {
return nil
}
#objc func buttonTapped() {
delegate?.customCellDidPressUrlButton(self)
}
}
Then, in the controller, set itself as a delegate and get the indexPath trough the proper method, indexPath(for:)
class YourTableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourTableViewCell
cell.delegate = self
return cell
}
}
extension YourTableViewController: YourTableViewCellDelegate {
func customCellDidPressUrlButton(_ yourTableCell: YourTableViewCell) {
guard let indexPath = tableView.indexPath(for: yourTableCell) else { return }
print("Link button pressed at \(indexPath)")
}
}
Then use that indexPath to grab the correct URL and present it from your table viewcontroller with a SFSafariViewController.
Swift 4
This is best way to get indexPath using touchPoint
class YourTableViewController: UITableViewController {
// ...
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SwiftyCell", for: indexPath) as! SwiftyTableViewCell
cell.label.text = "This is cell number \(indexPath.row)"
// WRONG! When cells get reused, these actions will get added again! That's not what we want.
// Of course, we could get around this by jumping through some hoops, but maybe there's a better solution...
cell.yourButton.addTarget(self, action: #selector(self.yourButtonTapped(_:)), for: .touchUpInside)
return cell
}
func yourButtonTapped(_ sender: Any?) {
let point = tableView.convert(sender.center, from: sender.superview!)
if let wantedIndexPath = tableView.indexPathForItem(at: point) {
let cell = tableView.cellForItem(at: wantedIndexPath) as! SwiftyCell
}
}
// ...
}
For more details you can follow this tutorials
Just create UIButton object in viewDidLoad and add this button as a sub view on cell in cellForRowAtIndexPath function. Take Burton's frame as per your requirement.

UISwitch state in Tableviewcell resets when user scrolls - Swift

I've searched for a solutions on this issue but none seem to work for my use case.
I have a table inside a viewcontroller and the issue I am facing is that when scrolling the UISwitch state is reset to OFF. I understand table cells are reused, but how do I implement a solution that will restore the state of UISwitch when a user scrolls based on my code below
import UIKit
class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var mylabel: UILabel!
var myString = String()
#IBAction func stirrBtn(_ sender: AnyObject) {
}
var timeSelected = String()
var selectedTimeArr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = myString
self.timeSelected = myString
}
func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
let kValue = (sender.tag + 1)
let keyValue = String(kValue)
if sender.isOn {
recipeSettings.boolStirrSwitch[keyValue] = true
recipeSettings.switchedOnArr.append(keyValue)
} else {
recipeSettings.boolStirrSwitch[keyValue] = false
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let stringNum = Int(self.timeSelected)
recipeSettings.recipeTimeSet2 = stringNum!
return(stringNum)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
// Process data displayed in rows(minutes)
let endTime = Int(self.timeSelected)
let startTime = Int(1)
// Recipe time array
let timeArray: [Int] = Array(startTime...endTime!)
let stringTimeArr = timeArray.map{String($0)}
// Save time array to global variable
recipeSettings.recipeTimeSetArr = stringTimeArr
// Create a boolean Array to hold all default false booleans
let defBool: Bool = false
var defBoolArr: [Bool] = []
// Fill the array with the defaults boolean
for _ in 0..<stringTimeArr.count{defBoolArr.append(defBool)}
// Map the array to global dictionary containing the Time in an array and default "false" value
for i in 0..<stringTimeArr.count {
recipeSettings.boolStirrSwitch[stringTimeArr[i]] = defBoolArr[i]
}
// Add the minutes to cell table
cell.textLabel?.text = stringTimeArr[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
As you can see in my code I do save the state of each UI switch in a global variable dictionary. How can I solve the issue of UISwitch changing states based on this code? All help is appreciated. Thanks in advance
var switchState = [String : Bool]()
your recipeSettings.boolStirrSwitch should be decleard like that.
As you are using timeSelected as numberOfRowsInSection as showing
your cell.textLabel from that so you don't need extra stringTimeArr
for that.
All the processing you do in cellForRowAt it will happen again and
again table cells are reused so for setting up data do it in another
function then reload TableView.
Solution for your problem should be look like that.
import UIKit
class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
//make tableView IBOutlet for reloading data
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var mylabel: UILabel!
var myString = String()
#IBAction func stirrBtn(_ sender: AnyObject) {
}
var timeSelected = String()
var selectedTimeArr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = myString
self.timeSelected = myString
self.setdefaultSwitchState()
}
//recipeSettings.boolStirrSwitch should be decleard like that
var switchState = [String : Bool]()
//setDeaultSwitchState
func setdefaultSwitchState(){
if let timeSelected = Int(self.timeSelected){
for value in 0..<timeSelected{
switchState["\(value)"] = false
//or
//recipeSettings.boolStirrSwitch["\(value)"] = false
}
}
self.tableView.reloadData()
}
#objc func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
let kValue = (sender.tag + 1)
let keyValue = String(kValue)
if sender.isOn {
switchState[keyValue] = true
} else {
switchState[keyValue] = false
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let stringNum = Int(self.timeSelected)
recipeSettings.recipeTimeSet2 = stringNum!
return(stringNum)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
cell.textLabel?.text = "\(indexPath.row + 1)"
if let switchState = switchState["\(indexPath.row)"] {
if switchState{
switchView.isOn = true
}else{
switchView.isOn = false
}
}else{
switchView.isOn = false
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

How to detect one button in tableview cell

How to detect one button in UITableviewCell, I have 10 UIButton in UITableViewCell, next when I click on UIButton then it detects multiple buttons, (as like odd number list). my UITableView is with paging enabled. Here is my all code.
TableView
class HomeViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var homeTableView: UITableView!
let mainArray = [["1","2","3","4"],["5","6","7","8"],["9","10","11","12"],["13","14","15","16"]]
override func viewDidLoad() {
super.viewDidLoad()
self.homeTableView.delegate = self
self.homeTableView.dataSource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return mainArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mainArray[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.view.frame.size.height
}
}
TableViewCell
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var bookMarkBtn: UIButton!
#IBAction func bookMarkBtnAction(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if(sender.isSelected == true)
{
sender.setImage(UIImage(named:"favorite_blue"), for: UIControlState.normal)
}
else
{
sender.setImage(UIImage(named:"favorite_white"), for: UIControlState.normal)
}
}
}
To detect a UIButton in a UITableViewCell, you can follow any of the below approaches:
1. Use UIButton IBOutlets
You can create an IBOutlet corresponding to each UIButton in the UITableViewCell and use those outlets to identify which button action is performed.
Example:
class CustomCell: UITableViewCell
{
#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
#IBOutlet weak var button3: UIButton!
#IBOutlet weak var button4: UIButton!
#IBOutlet weak var button5: UIButton!
#IBAction func onTapButton(_ sender: UIButton)
{
if sender === button1
{
//button1 specific code here
}
else if sender === button2
{
//button2 specific code here
}
//and so on..
}
}
2. Use UIButton Tag property
You can provide a tag value to each of the UIButton present in the UITableViewCell and then use that tag to identify the specific button.
Example:
class CustomCell: UITableViewCell
{
#IBAction func onTapButton(_ sender: UIButton)
{
if sender.tag == 1
{
//button1 has a tag = 1
//button1 specific code here
}
else if sender.tag == 2
{
//button2 has a tag = 2
//button2 specific code here
}
//and so on..
}
}
Edit:
For setting different images in selected/unselected state of UIButton, you can use storyboard for that:
For Unselected state:
For Selected state:
Let me know if you still face any issues.
In your cellForRowAt method, do add tag number to the buttons
cell.bookMarkBtn.tag = indexPath.row;
Then
#IBAction func bookMarkBtnAction(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if(sender.tag == 0)
{
...
} else if (sender.tag == 1)
{
...
}
}
Create protocol
protocol HomeTableViewCellDelegate {
func bookMarkBtnTapped(btn: UIButton)
}
class HomeTableViewCell: UITableViewCell {
#IBOutlet weak var bookMarkBtn: UIButton!
//add delegate var for protocol
var delegate: HomeTableViewCellDelegate?
#IBAction func bookMarkBtnAction(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if(sender.isSelected == true)
{
sender.setImage(UIImage(named:"favorite_blue"), for: UIControlState.normal)
}
else
{
sender.setImage(UIImage(named:"favorite_white"), for: UIControlState.normal)
}
//set this which button is pressed
self.delegate?.bookMarkBtnTapped(btn: sender)
}
}
HomeViewController implement HomeTableViewCellDelegate method
class HomeViewController: HomeTableViewCellDelegate {
func bookMarkBtnTapped(btn: UIButton) {
// here btn is book mark button tapped by user from tableview cell
}
}
Use button tag for this.
In tableViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
cell.bookMarkBtn.tag = indexPath.row
cell.bookMarkBtn.addTarget(self, action: #selector(self. bookMarkBtnAction), for: .touchUpInside)
return cell
}
#objc func bookMarkBtnAction(sender: UIButton) {
if sender.tag == 0 { //or which indexpath do you want.
//code
} else if sender.tag == 1 {
//code
}
..
}
remove #IBAction func bookMarkBtnAction(_ sender: UIButton) from tableviewcell class

Resources