I have a collection view in swift in where it needs to store which button is pressed last. These buttons consist of A, B, C, D, this is like a quiz game.
Code:
extension QuestionCell {
func configure(with model: QuestionCellModel) {
factLabel.text = model.fact
questionLabel.text = model.question
let views = answersStack.arrangedSubviews
for view in views {
view.removeFromSuperview()
}
for (index, answer) in model.answers.enumerated() {
print(index)
let answerLabel = UILabel()
answerLabel.text = answer
answersStack.addArrangedSubview(answerLabel)
let answerButton = UIButton()
answerButton.tag = index
let imageNormal = UIImage(named: "circle_empty")
answerButton.setImage(imageNormal, for: .normal)
let imageSelected = UIImage(named: "circle_filled")
answerButton.setImage(imageSelected, for: .selected)
answerButton.setTitleColor(.black, for: .normal)
answerButton.addTarget(self, action: #selector(answerPressed(_:)), for: .touchUpInside)
answersStack.addArrangedSubview(answerButton)
}
}
So with this it is able to print the index, but it should know which was the last button they selected, when they were done (Buttons: A,B,C,D). Based on the index it should store assigned values of each collection view cell(There are 5 question in the quiz). I have not figured out a way on how to solve this question because I am not sure the computer will store multiple index's in the collection view(Like how would the computer know when you click the done with quiz button what was the last index it chose for each question?) I hope this makes sense!
Thanks
Related
I am trying to push to a new view controller when I click the quiz button I implemented. I set it up as below:
quizButton = UIButton()
quizButton.setTitle(" Quiz ", for: .normal)
quizButton.backgroundColor = .lightGray
quizButton.layer.cornerRadius = 9
quizButton.translatesAutoresizingMaskIntoConstraints = false
quizButton.addTarget(self, action: #selector(takeQuiz), for: .touchUpInside)
view.addSubview(quizButton)
and I defined the function takeQuiz as below, where there is a separate view controller called QuizViewController:
#objc func takeQuiz() {
let newViewController = QuizViewController()
navigationController?.pushViewController(newViewController, animated: true)
}
I'm not sure if it was necessary for me to use delegates here, since I am not trying to relay any information from one view controller to the other. Let me know, thanks in advance.
I'm adding labels and buttons to a TextView dynamically. This is driven by looping through arrays containing label names, button names, and button function names. For brevity and simplicity, I've changed the code here to use hard-coded indexes rather than a loop, and I did not include the label- and button-creation functions. The labels are created just fine. The first button is also created just fine, since I specify Button1Clicked as the #selector argument. The second button is created correctly only if I specify Button2Clicked as the #selector argument. If I attempt to reference an array in the button #selector argument, I receive the compiler error "Argument of '#selector' does not refer to an '#objc' method, property, or initializer". Assuming it is possible to use an array containing the #objc function name as an argument to the #selector, can someone please provide the appropriate syntax for me? I'm using Swift 5 and Xcode 11.2. Thank you in advance for your assistance.
#objc func Button1Clicked(sender: UIButton) {
print("You pressed button 1")
}
#objc func Button2Clicked(sender: UIButton) {
print("You pressed button 2")
}
.
.
.
var labelNames = [UILabel]()
let Label1:UILabel = UILabel()
let Label2:UILabel = UILabel()
labelNames = [Label1, Label2]
var buttonNames = [UIButton]()
let Button1:UIButton = UIButton()
let Button2:UIButton = UIButton()
buttonNames = [Button1, Button2]
let buttonSelectorNames = ["Button1Clicked", "Button2Clicked"]
configureLabel(labelNameIn: labelNames[0],
textIn: "aaaaa",
textColorIn: appColorWhite,
backgroundColorIn: appColorBlue,
yPositionIn: 0)
statusTextview.addSubview(labelNames[0])
configureLabel(labelNameIn: labelNames[1],
textIn: "-- bbbbb",
textColorIn: appColorWhite,
backgroundColorIn: appColorBlue,
yPositionIn: 25)
statusTextview.addSubview(labelNames[1])
configureButton(buttonNameIn: buttonNames[0],
xPositionIn: 0,
yPositionIn: 50,
textIn: "B1",
textColorIn: appColorBlack,
backgroundColorIn: appColorBrightGreen,
textViewIn: statusTextview)
buttonNames[0].addTarget(self,
action: #selector(Button1Clicked),
for: .touchUpInside)
statusTextview.addSubview(buttonNames[0])
configureButton(buttonNameIn: buttonNames[1],
xPositionIn: 100,
yPositionIn: 50,
textIn: "B2",
textColorIn: appColorBlack,
backgroundColorIn: appColorBrightGreen,
textViewIn: statusTextview)
buttonNames[1].addTarget(self,
action: #selector(buttonSelectorNames[1]),
for: .touchUpInside)
statusTextview.addSubview(buttonNames[1])
you don’t need to define button click event for each button.you can define common function and assign it to all buttons in the loop.then you can specify through button tag
in your loop assign the current index as button tag
buttonNames[currentIndex].tag = currentIndex
buttonNames[currentIndex].addTarget(self,
action: #selector(didButtonClicked(_ :)),
for: .touchUpInside)
button click function
#objc func didButtonClicked(_ sender : UIButton){
switch sender.tag{
case 0: //clicked button with tag 0
case 1: //clicked button with tag 1
default: break
}
}
In the past, I have a deal with the same type of requirement. I was doing it by storing the selector in Array.
Please refer to the code snippets. I am sure it will help you.
Code:
class ViewController: UIViewController {
let selector = [#selector(Button1Clicked),#selector(Button2Clicked)]
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(frame: self.view.bounds)
self.view.addSubview(btn)
btn.addTarget(self, action: selector[0], for: .touchUpInside)
}
#objc func Button1Clicked(){
print("Button1Clicked")
}
#objc func Button2Clicked(){
}
}
Output:
In my tableView Cell class, I use didSet method to setup my UI values and in there I have an array of string from api which I use to create an array of buttons and append it to a UIStackView
var pollDataInPollCell: PollModel? {
didSet{
if let pollOptions = pollDataInPollCell?.poll_detail {
//sample pollOptions = ["Button1","Button2","Button3","Button4"]
for index in pollOptions {
let bt = UIButton(type: .system)
bt.setTitleColor(.blue, for: .normal)
bt.setTitle(index, for: .normal)
optionBtnStackView.addArrangedSubview(bt)
}
}
}
}
my stackView outside of didSet
var optionBtnStackView: UIStackView = {
let sv = UIStackView()
sv.axis = .vertical
sv.distribution = .fillEqually
sv.spacing = 5
return sv
}()
everything works great at launch however, when I scroll down and up, my stackview is adding 4 more buttons. It has 4 at launch and then 8 and then 12 and keep increasing by 4 whenever I scroll up and down my app. I know the problem is from tableView dequeueReusableCell but I couldn't find a way to fix this issue. Any suggestions? Thank you.
Use below code in your didSet
var pollDataInPollCell: PollModel? {
didSet{
for view in optionBtnStackView.subviews {
optionBtnStackView.removeArrangedSubview(view)
view.removeFromSuperview()
}
if let pollOptions = pollDataInPollCell?.poll_detail {
//sample pollOptions = ["Button1","Button2","Button3","Button4"]
for index in pollOptions {
let bt = UIButton(type: .system)
bt.setTitleColor(.blue, for: .normal)
bt.setTitle(index, for: .normal)
optionBtnStackView.addArrangedSubview(bt)
}
}
}
}
I know how to add tags in main.storyboard files, but now I am working on creating everything programmatically. However, I couldn't find anything online that tells me how to add tags to a button. I tried to read the apple documentation but don't know how to implement it.
Here is for example how I created my button, how can I add a tag to it, so that when I make multiple buttons and want to link them to a single action I can know what button has been pressed?
let buttonOne() : UIButton {
let button = UIButton(type: .system)
button.backgroundColor = .red
return button
}()
Try this:
let buttonOne() : UIButton {
let button = UIButton(type: .system)
button.backgroundColor = .red
button.tag = 2
return button
}()
Declare The Button
let menuChooseButton = UIButton()
menuChooseButton.frame.origin.y = 0
menuChooseButton.frame.origin.x = xPosition
menuChooseButton.frame.size.width = subViewWidth
menuChooseButton.frame.size.height = subViewHeight
menuChooseButton.backgroundColor = .clear
menuChooseButton.setTitle("", for: .normal)
menuChooseButton.tag = i
menuChooseButton.addTarget(self, action: #selector(menuSelectAction), for: .touchUpInside)
menuScrollView.addSubview(menuChooseButton)
Define Button Action
#objc func menuSelectAction(sender: UIButton!){
var tagNo: Int = sender.tag
if tagNo == 0{
// Whatever you want
}
}
I hope I am giving enough information by just showing the "cellForRowAtIndexPath" segment. The entire program is too long. Each row in my tableView represents a player and each player has four buttons associated with him/her. Based on an action of the player, I will press one of the buttons to record that action and keep a tally for each of the button presses in the titleLabel of that button. I have created an array for each button to keep track of the number of button presses in each of the buttons, "plyZeroes", "plrOnes", "plrTwoes", and "plrThrees". I use these arrays (plrZeroesArray, plyrOnesArray, etc) to save the correct value and then reload the button titleLabel with this correct value just before it it is redisplayed (in the event it has scrolled off the screen and then reappear). At least that's what I think I am doing. But it may be my lack of understanding of how cellForRowAtIndexPath works.
In the code segment below I have set breakpoints and have placed "print" statements at various places and I am confident that the array has assigned the correct information to each one of the "plrxxx" buttons just before the "return cell" statement. However, when I run the application and if I scroll the device (iPad) enough, the count (text of the label) shown on the device is different than the value in the array (different than the value that was assigned to the button's textLabel). If I scroll again to show the cell, the values become correct. Basically when some cells disappear and reappear, the contain incorrect values about 30%- 50% of the time. Any ideas?
ps: there is another object "plrAvg" that is a label and I do the same saving of the data before it is returned, and it works fine all the time.
var plrNumbers: NSMutableArray! = NSMutableArray()
var players: NSMutableArray! = NSMutableArray()
var plrAverageArray = [String](count: 99, repeatedValue: "0")
var plrZeroesArray = [String](count: 99, repeatedValue: "0")
var plrOnesArray = [String](count: 99, repeatedValue: "0")
var plrTwosArray = [String](count: 99, repeatedValue: "0")
var plrThreesArray = [String](count: 99, repeatedValue: "0")
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CustomCell
// Poputate the players' info, average, and last action//
cell.hiddenLabel.text = ("\(indexPath.row)")
cell.plrNumbers.text = (plrNumbers[indexPath.row] as! String)
cell.plrNames.text = (players[indexPath.row] as! String)
cell.plrZeroes.addTarget(self, action: "handleButtonPressed:", forControlEvents: .TouchUpInside)
cell.plrOnes.addTarget(self, action: "handleButtonPressed:", forControlEvents: .TouchUpInside)
cell.plrTwos.addTarget(self, action: "handleButtonPressed:", forControlEvents: .TouchUpInside)
cell.plrThrees.addTarget(self, action: "handleButtonPressed:", forControlEvents: .TouchUpInside)
cell.btnUndoLastPlrAction.addTarget(self, action: "handleButtonPressed:", forControlEvents: .TouchUpInside)
//restore the player's average in case it was lost because it scrolled off the screen
cell.plrAvg.text = (plrAverageArray[indexPath.row])
//restore the button text in case it was lost because it scrolled off the screen
cell.plrZeroes.titleLabel?.text = (plrZeroesArray[indexPath.row])
cell.plrOnes.titleLabel?.text = (plrOnesArray[indexPath.row])
cell.plrTwos.titleLabel?.text = (plrTwosArray[indexPath.row])
cell.plrThrees.titleLabel?.text = (plrThreesArray[indexPath.row])
print("Buttons \(indexPath.row)] = ", plrZeroesArray[indexPath.row] + plrOnesArray[indexPath.row] + plrTwosArray[indexPath.row] + plrThreesArray[indexPath.row])
return cell
}