how to create radio buttons dynamically in swift? - ios

I have the following buttons which are adding dynamically based on some condition. Now i need to change all added buttons behaviour as radio buttons. so that I can do some actions based on the selection..
var posX = 0
var posY = 0
if trim.contains("0"){
print("contaim 0")
let button1 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button1.setTitleColor(UIColor.blackColor(), forState: .Normal)
button1.setTitle("No", forState: .Normal)
button1.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button1.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button1)
posX = 60
}
if trim.contains("1") {
print("contaim 1")
let button2 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button2.setTitleColor(UIColor.blackColor(), forState: .Normal)
button2.setTitle("Less", forState: .Normal)
button2.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button2.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button2)
posX = posX + 60
}
if trim.contains("2"){
print("contaim 2")
let button3 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button3.setTitleColor(UIColor.blackColor(), forState: .Normal)
button3.setTitle("Half", forState: .Normal)
button3.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button3.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button3)
posX = posX + 60
}
I have set the buttonAction methods as below buts its not working
func buttonAction(sender: UIButton!) {
print("Button tapped")
sender.setImage(UIImage(named: "checkboxredtick.png")!, forState: .Normal)
}

let buttons = [UIButton]()
// create button1
let button1 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button1.setTitleColor(UIColor.blackColor(), forState: .Normal)
button1.setTitle("No", forState: .Normal)
button1.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
// if the selected button cannot be reclick again, you can use .Disabled state
button1.setImage(UIImage(named: "checkboxredtick.png")!, forState: .Selected)
button1.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button1)
buttons.append(button1)
// create other buttons and add into buttons ...
func buttonAction(sender: UIButton!){
for button in buttons {
button.selected = false
}
sender.selected = true
// you may need to know which button to trigger some action
// let buttonIndex = buttons.indexOf(sender)
}

In case anyone finds this useful. Here is an example of how I use DLRadioButton library (https://github.com/DavydLiu/DLRadioButton) to create RadioButtons dynamically.
You can check a complete small project to show a working code in here https://github.com/omhack/DynamicRadioButtons
import UIKit
import DLRadioButton
//Delegate to manage the Polls
protocol QuestionsDialogDelegate : class{
func questionsAnswered(polls: [Poll])
}
class QuestionsDialog: UIViewController {
#IBOutlet weak var stackView: UIStackView!
#IBOutlet var rootView: UIView!
#IBOutlet weak var nestedView: UIView!
weak var delegate: QuestionsDialogDelegate?
var questions : [Question]!
var polls = [Poll]()
var serviceType : Int = 0
var indexView : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
//setting the stack view properties
stackView.alignment = UIStackViewAlignment.leading
stackView.axis = .vertical
}
//this is where the heavy logic, to create the dynamic radio buttons takes place
func showQuestions(){
if(questions.count <= 1){
rootView.frame.size.height = 200
nestedView.frame.size.height = 200
}else{
rootView.frame.size.height = 400
nestedView.frame.size.height = 400
}
for question in questions{
var otherButtons : [DLRadioButton] = []
let frame1 = CGRect(x: self.view.frame.size.width / 2 - 131, y: 350, width: 262, height: 17);
//we create a base radio button to use it as an anchor view
let firstRadioButton = createRadioButton(frame: frame1, title: "", color: UIColor.purple);
let label = UILabel()
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 17.0)
label.textColor = UIColor.darkGray.withAlphaComponent(0.85)
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.25
label.frame = CGRect(x: 0, y: 0, width: 200, height: 30)
label.text = question.question
self.stackView.insertArrangedSubview(label, at: self.indexView)
self.indexView += 1
let poll = Poll()
poll.idQuestion = question.idQuestion
var i = 0;
for answer in question.answers{
let frame = CGRect(x: self.view.frame.size.width / 2 - 131, y: 380 + 30 * CGFloat(i), width: 300, height: 17);
let radioButton = createRadioButton(frame: frame, title: answer.answer! + " ", color: UIColor.purple)
radioButton.tag = answer.idAnswer
radioButton.params["poll"] = poll
otherButtons.append(radioButton)
self.stackView.insertArrangedSubview(radioButton, at: self.indexView)
i += 1;
self.indexView += 1
}
firstRadioButton.otherButtons = otherButtons
firstRadioButton.isHidden = true
firstRadioButton.otherButtons[1].isSelected = true
}
}
//Method to create a custom button
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> MyDLUIButton {
let radioButton = MyDLUIButton(frame: frame);
radioButton.titleLabel?.translatesAutoresizingMaskIntoConstraints = false
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: []);
radioButton.setTitleColor(UIColor.darkGray, for: []);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
radioButton.addTarget(self, action: #selector(QuestionsDialog.selectedAnswer(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(radioButton);
return radioButton;
}
#objc func selectedAnswer(_ sender: MyDLUIButton){
let poll = sender.params["poll"] as? Poll
poll?.idAnswer = sender.tag
if let row = self.polls.index(where: {$0.idQuestion == poll?.idQuestion}) {
self.polls[row] = poll!
}else{
self.polls.append(poll!)
}
print("polls size: \(self.polls.count)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidDisappear(_ animated: Bool) {
if(self.polls.count < self.questions.count){
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "questionsDialogDismissed"), object: nil)
}
}
#IBAction func requestService(_ sender: UIButton) {
delegate?.questionsAnswered(polls: self.polls)
}
}
class MyDLUIButton: DLRadioButton{
var params: Dictionary<String, Any>
override init(frame: CGRect) {
self.params = [:]
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
self.params = [:]
super.init(coder: aDecoder)
}
}

I would create a tag for every UIButton, then add your UIButton to be send to your ButtonAction:
button.tag = 0
button.addTarget(object, action: #selector(YourViewController.buttonAction(_:)),
forControlEvents: .TouchUpInside)
func buttonAction(sender: UIButton!) {
let selectedButton = sender as! UIButton
print(selectedButton.tag) // here stands the correct button which is pressed
}
You could also create an Array containing all Buttons, for example:
let myButtons = [UIButton]()
let button1 = UIButton()...
button1.tag = 0
myButtons.add(button1)
And now change it like this way:
myButtons[0].setImage(.....)
Where 0 is your first button (so with tag 0) // you should set your tags in the same order in which you append it to your myButtons Array.

Related

How to create a button programmatically with for loop in swift

I created buttons with for loop and i want to print button number when pressed to button. How can i do this?
for x in 0..<5 {
let button = UIButton(frame: CGRect(x: CGFloat(x) * view.frame.size.width + 10 , y: 40, width: view.frame.size.width - 20, height: 30))
buttonKontrol = x
print(buttonKontrol)
button.setTitle("Button", for: .normal)
button.backgroundColor = .white
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(btntapped), for: .touchUpInside)
scrollView.addSubview(button)
}
and objc func:
#objc func btntapped(_ sender: UIButton) {
print("button tapped")
}
Various ways to do that...
find the frame of the tapped button (not a good approach, but for your simple example it could work)
use the .tag property of the button
evaluate the .currentTitle property of the button
add the buttons to an array... on tap, use let buttonNumber = btnsArray.firstIndex(of: sender)
There are lots of ways, but a 'Swifty' way might be like this:
final class TargetAction {
let work: () -> Void
init(_ work: #escaping () -> Void) {
self.work = work
}
#objc func action() {
work()
}
}
class ViewController: UIViewController {
private var tas: [TargetAction] = []
override func viewDidLoad() {
super.viewDidLoad()
(0...4).forEach { x in
let button = UIButton(frame: CGRect(x: CGFloat(x) * 50 , y: 40, width: 44, height: 44))
button.setTitleColor(.black, for: .normal)
button.setTitle("\(x)", for: .normal)
let ta =
TargetAction {
print(x)
}
tas.append(ta)
button.addTarget(ta, action: #selector(TargetAction.action), for: .touchUpInside)
view.addSubview(button)
}
}
}

Key board will show notification. does not give notification of keyboard appearing

I have the following notification setup in my viewDidLoad() of my custom keyboard extension:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
and this is the function I call outside of my viewDidLoad():
#objc func keyboardWillShow(_ notification: NSNotification) {
if let keyboardRect = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
print(keyboardRect.height)
ScreenHeight = Int(keyboardRect.height)
}
}
However, I set a breakpoint inside of my keyboardWillShow() function and it is never triggered. Is there something else I have to do to get the size of the keyboard before it shows?
I am trying to dynamically adjust the size of elements programmatically inserted into my keyboard.
Let me know if more information is necessary or if this is an obvious fix.
Full Code:
class KeyboardViewController: UIInputViewController {
#IBOutlet var nextKeyboardButton: UIButton! = UIButton(type: .system)
var centralManager: CBCentralManager!
var NUB5: CBPeripheral!
var characteristics = [CBCharacteristic]()
var connection: UILabel = UILabel()
var serialNum: UILabel = UILabel()
var serial: String = ""
var ScreenHeight = 0
let cornerRadii = 4
//setup Number buttons
var num1: UIButton = UIButton()
var num2: UIButton = UIButton()
var num3: UIButton = UIButton()
var num4: UIButton = UIButton()
var num5: UIButton = UIButton()
var num6: UIButton = UIButton()
var num7: UIButton = UIButton()
var num8: UIButton = UIButton()
var num9: UIButton = UIButton()
var num0: UIButton = UIButton()
var spaceBar: UIButton = UIButton()
var plus: UIButton = UIButton()
var minus: UIButton = UIButton()
var back: UIButton = UIButton()
var left: UIButton = UIButton()
var right: UIButton = UIButton()
var period: UIButton = UIButton()
var comma: UIButton = UIButton()
var returnKey: UIButton = UIButton()
let screensize: CGRect = UIScreen.main.bounds
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
var keyboard: UIView!
func loadInterface() {
// load the nib file
var calculatorNib = UINib(nibName: "keyboard", bundle: nil)
// instantiate the view
keyboard = (calculatorNib.instantiate(withOwner: self, options: nil)[0] as! UIView)
// add the interface to the main view
view.addSubview(keyboard)
// copy the background color
view.backgroundColor = keyboard.backgroundColor
ScreenHeight = Int(self.accessibilityFrame.height)
print(ScreenHeight)
}
super.viewDidLoad()
loadInterface()
self.centralManager = CBCentralManager(delegate: self, queue: nil)
//Setup Labels
let width = screensize.width
let height = CGFloat(200) //subtract 10 from total screensize to give space for connection indicator
let screensize = self.view.bounds.size
//ScreenHeight = Int(height)
connection.frame = CGRect(x: 0,y: 0,width: width,height: 10)
//TODO
serialNum.frame = CGRect(x: width/2+5, y:10,width: width/2 - 10,height:15)
spaceBar.frame = CGRect(x: width*4/5+4, y: height/4+10, width: width/5, height: height/4)
num1.frame = CGRect(x:width/5,y: 10, width: width/5,height: height/4)
num2.frame = CGRect(x:width*2/5,y: 10, width: width/5,height: height/4)
num3.frame = CGRect(x:width*3/5,y: 10, width: width/5,height: height/4)
num4.frame = CGRect(x:width/5+1,y: height/4+10, width: width/5,height: height/4)
num5.frame = CGRect(x:width*2/5+2,y: height/4+10, width: width/5,height: height/4)
num6.frame = CGRect(x:width*3/5+3,y: height/4+10, width: width/5,height: height/4)
num7.frame = CGRect(x:width/5+1,y: height/2+10, width: width/5,height: height/4)
num8.frame = CGRect(x:width*2/5+2,y: height/2+10, width: width/5,height: height/4)
num9.frame = CGRect(x:width*3/5+3,y: height/2+10, width: width/5,height: height/4)
num0.frame = CGRect(x:width*2/5+3,y: 3*height/4+10, width: width/5,height: height/4)
plus.frame = CGRect(x:0,y: 10, width: width/5,height: height/4)
minus.frame = CGRect(x:0,y: height/4+10, width: width/5,height: height/4)
back.frame = CGRect(x:width*4/5,y:10,width:width/5,height:height/4)
right.frame = CGRect(x: width*4/5+4, y: height/2+10, width: width/5, height: height/4)
left.frame = CGRect(x:0,y: height/2+10, width: width/5,height: height/4)
nextKeyboardButton.frame = CGRect(x:0,y: 3*height/4+10, width: width/5,height: height/4)
period.frame = CGRect(x:width/5,y: 3*height/4+10, width: width/5,height: height/4)
comma.frame = CGRect(x:width*3/5+2,y: 3*height/4+10, width: width/5,height: height/4)
returnKey.frame = CGRect(x:width*4/5+3,y: height*3/4+10, width: width/5,height: height/4)
num1.addTarget(self,action: #selector(addOne), for: .touchUpInside)
num2.addTarget(self,action: #selector(addTwo), for: .touchUpInside)
num3.addTarget(self,action: #selector(addThree), for: .touchUpInside)
num4.addTarget(self,action: #selector(addFour), for: .touchUpInside)
num5.addTarget(self,action: #selector(addFive), for: .touchUpInside)
num6.addTarget(self,action: #selector(addSix), for: .touchUpInside)
num7.addTarget(self,action: #selector(addSeven), for: .touchUpInside)
num8.addTarget(self,action: #selector(addEight), for: .touchUpInside)
num9.addTarget(self,action: #selector(addNine), for: .touchUpInside)
num0.addTarget(self,action: #selector(addZero), for: .touchUpInside)
spaceBar.addTarget(self,action: #selector(space), for: .touchUpInside)
plus.addTarget(self, action: #selector(plusSign), for: .touchUpInside)
minus.addTarget(self, action: #selector(minusSign), for: .touchUpInside)
back.addTarget(self, action: #selector(deleteOne), for: .touchUpInside)
left.addTarget(self, action: #selector(leftOne), for: .touchUpInside)
right.addTarget(self, action: #selector(rightOne), for: .touchUpInside)
nextKeyboardButton.addTarget(self, action: #selector(handleInputModeList(from:with:)), for: .allTouchEvents)
period.addTarget(self, action: #selector(addPeriod), for: .touchUpInside)
comma.addTarget(self, action: #selector(addComma), for: .touchUpInside)
returnKey.addTarget(self, action: #selector(returnButton), for: .touchUpInside)
num1.setTitle("1", for: .normal)
num2.setTitle("2", for: .normal)
num3.setTitle("3", for: .normal)
num4.setTitle("4", for: .normal)
num5.setTitle("5", for: .normal)
num6.setTitle("6", for: .normal)
num7.setTitle("7", for: .normal)
num8.setTitle("8", for: .normal)
num9.setTitle("9", for: .normal)
num0.setTitle("0", for: .normal)
spaceBar.setTitle("SPACE", for: .normal)
back.setTitle("<-", for: .normal)
plus.setTitle("+", for: .normal)
minus.setTitle("-", for: .normal)
left.setTitle("<", for: .normal)
right.setTitle(">", for: .normal)
nextKeyboardButton.setTitle("NEXT", for: .normal)
period.setTitle(".", for: .normal)
comma.setTitle(",", for: .normal)
returnKey.setTitle("Return", for: .normal)
num1.layer.cornerRadius = CGFloat(cornerRadii)
num2.layer.cornerRadius = CGFloat(cornerRadii)
num3.layer.cornerRadius = CGFloat(cornerRadii)
num4.layer.cornerRadius = CGFloat(cornerRadii)
num5.layer.cornerRadius = CGFloat(cornerRadii)
num6.layer.cornerRadius = CGFloat(cornerRadii)
num7.layer.cornerRadius = CGFloat(cornerRadii)
num8.layer.cornerRadius = CGFloat(cornerRadii)
num9.layer.cornerRadius = CGFloat(cornerRadii)
num0.layer.cornerRadius = CGFloat(cornerRadii)
spaceBar.layer.cornerRadius = CGFloat(cornerRadii)
plus.layer.cornerRadius = CGFloat(cornerRadii)
minus.layer.cornerRadius = CGFloat(cornerRadii)
back.layer.cornerRadius = CGFloat(cornerRadii)
left.layer.cornerRadius = CGFloat(cornerRadii)
right.layer.cornerRadius = CGFloat(cornerRadii)
nextKeyboardButton.layer.cornerRadius = CGFloat(cornerRadii)
period.layer.cornerRadius = CGFloat(cornerRadii)
comma.layer.cornerRadius = CGFloat(cornerRadii)
returnKey.layer.cornerRadius = CGFloat(cornerRadii)
num5.layer.borderWidth = CGFloat(1)
num1.setTitleColor(UIColor.black, for: .normal)
num2.setTitleColor(UIColor.black, for: .normal)
num3.setTitleColor(UIColor.black, for: .normal)
num4.setTitleColor(UIColor.black, for: .normal)
num5.setTitleColor(UIColor.black, for: .normal)
num6.setTitleColor(UIColor.black, for: .normal)
num7.setTitleColor(UIColor.black, for: .normal)
num8.setTitleColor(UIColor.black, for: .normal)
num9.setTitleColor(UIColor.black, for: .normal)
num0.setTitleColor(UIColor.black, for: .normal)
spaceBar.setTitleColor(UIColor.black, for: .normal)
plus.setTitleColor(UIColor.black, for: .normal)
minus.setTitleColor(UIColor.black, for: .normal)
back.setTitleColor(UIColor.black, for: .normal)
left.setTitleColor(UIColor.black, for: .normal)
right.setTitleColor(UIColor.black, for: .normal)
period.setTitleColor(UIColor.black, for: .normal)
comma.setTitleColor(UIColor.black, for: .normal)
nextKeyboardButton.setTitleColor(UIColor.black, for: .normal)
returnKey.setTitleColor(UIColor.black, for: .normal)
num1.backgroundColor = UIColor.white
num2.backgroundColor = UIColor.white
num3.backgroundColor = UIColor.white
num4.backgroundColor = UIColor.white
num5.backgroundColor = UIColor.white
num6.backgroundColor = UIColor.white
num7.backgroundColor = UIColor.white
num8.backgroundColor = UIColor.white
num9.backgroundColor = UIColor.white
num0.backgroundColor = UIColor.white
spaceBar.backgroundColor = UIColor.white
plus.backgroundColor = UIColor.white
minus.backgroundColor = UIColor.white
back.backgroundColor = UIColor.white
left.backgroundColor = UIColor.white
right.backgroundColor = UIColor.white
nextKeyboardButton.backgroundColor = UIColor.white
period.backgroundColor = UIColor.white
comma.backgroundColor = UIColor.white
returnKey.backgroundColor = UIColor.white
connection.text = "No Connection"
serialNum.text = "-"
connection.backgroundColor = UIColor.white
serialNum.backgroundColor = UIColor.white
connection.layer.cornerRadius = 4
serialNum.layer.cornerRadius = 4
self.view.addSubview(connection)
self.view.addSubview(serialNum)
self.view.addSubview(spaceBar)
self.view.addSubview(num1)
self.view.addSubview(num2)
self.view.addSubview(num3)
self.view.addSubview(num4)
self.view.addSubview(num5)
self.view.addSubview(num6)
self.view.addSubview(num7)
self.view.addSubview(num8)
self.view.addSubview(num9)
self.view.addSubview(num0)
self.view.addSubview(plus)
self.view.addSubview(minus)
self.view.addSubview(back)
self.view.addSubview(left)
self.view.addSubview(right)
self.view.addSubview(period)
self.view.addSubview(comma)
self.view.addSubview(nextKeyboardButton)
self.view.addSubview(returnKey)
}
#objc func returnButton(sender: UIButton){
textDocumentProxy.insertText("\n")
}
#objc func addPeriod(sender: UIButton){
textDocumentProxy.insertText(".")
}
#objc func addComma(sender: UIButton){
textDocumentProxy.insertText(",")
}
#objc func leftOne(sender: UIButton){
textDocumentProxy.adjustTextPosition(byCharacterOffset: -1)
}
#objc func rightOne(sender: UIButton){
textDocumentProxy.adjustTextPosition(byCharacterOffset: 1)
}
#objc func deleteOne(sender: UIButton){
textDocumentProxy.deleteBackward()
}
#objc func plusSign(sender: UIButton){
textDocumentProxy.insertText("+")
}
#objc func minusSign(sender: UIButton){
textDocumentProxy.insertText("-")
}
#objc func space(sender: UIButton){
textDocumentProxy.insertText(" ")
}
#objc func addOne(sender: UIButton){
textDocumentProxy.insertText("1")
textDocumentProxy.insertText(String(ScreenHeight))
}
#objc func addTwo(sender: UIButton){
textDocumentProxy.insertText("2")
}
#objc func addThree(sender: UIButton){
textDocumentProxy.insertText("3")
}
#objc func addFour(sender: UIButton){
textDocumentProxy.insertText("4")
}
#objc func addFive(sender: UIButton){
textDocumentProxy.insertText("5")
}
#objc func addSix(sender: UIButton){
textDocumentProxy.insertText("6")
}
#objc func addSeven(sender: UIButton){
textDocumentProxy.insertText("7")
}
#objc func addEight(sender: UIButton){
textDocumentProxy.insertText("8")
}
#objc func addNine(sender: UIButton){
textDocumentProxy.insertText("9")
}
#objc func addZero(sender: UIButton){
textDocumentProxy.insertText("0")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if self.centralManager.state == CBManagerState.poweredOn {
self.centralManager.scanForPeripherals(withServices: [lairdUUID], options: nil)
}
}
#objc func keyboardWillShow(_ notification: NSNotification) {
if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
let keyBoardRect = frame?.cgRectValue
ScreenHeight = Int(keyBoardRect!.height)
}
}
override func viewWillDisappear(_ animated: Bool) {
// super.viewWillDisappear(animated)
// if let centralManager = self.centralManager {
// if centralManager.state == CBManagerState.poweredOn {
// if let NUB5 = self.NUB5 {
// if peripheral.state == CBPeripheralState.connected {
// centralManager.cancelPeripheralConnection(NUB5)
// }
// }
// }
// }
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(_ textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(_ textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
}
For prevent crashes and for the best practice use
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
on viewWillAppear.
Since your method keyboardWillShow has a parameter you should change the syntax accordingly to inform the compiler exactly the method that it has to look for.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
What was happening is that the compiler will search for the method keyboardWillShow without any parameters which is not there, Hence doesn't execute anything.

Add border to buttons in iOS scroll view on click and remove border from other buttons

I have added buttons to horizontal Scroll View in iOS.
override func viewDidLoad() {
super.viewDidLoad()
setUpScrollView()
// Do any additional setup after loading the view, typically from a nib.
}
func setUpScrollView() {
let buttonPadding:CGFloat = 10
var xOffset:CGFloat = 10
for i in 0 ... 10 {
let button = UIButton()
button.tag = i
button.backgroundColor = UIColor.red
button.setTitle("\(i)", for: .normal)
if(button.tag==currentTag){
button.addTarget(self, action: #selector(btnTouchUnselect), for: UIControlEvents.touchUpInside)
}
else{
button.addTarget(self, action: #selector(btnTouch), for: UIControlEvents.touchUpInside)
}
button.frame = CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 70, height: 30)
xOffset = xOffset + CGFloat(buttonPadding) + button.frame.size.width;
scrollView.addSubview(button)
}
scrollView.contentSize = CGSize(width: xOffset, height: scrollView.frame.height)
}
#objc func btnTouch(button:UIButton){
print("tap touch",button.tag)
button.layer.borderColor = UIColor.black.cgColor
button.layer.borderWidth = 1.0
currentTag = button.tag
}
#objc func btnTouchUnselect(button:UIButton){
button.layer.borderColor = UIColor.white.cgColor
button.layer.borderWidth = 1.0
}
}
I want a button to get a different border color when the user clicks it and the others to stay black. But when I am using this code it turns all clicked button borders black and doesn't turn the clicked one white.
Aim Example:-Suppose I have 10 buttons, I want when button 1's is clicked then its border turns white and others' remain black; if button 2 is clicked then the borders of all turn black again including button 1, only the border of button 2 changes to white.
I need some guidance to achieve this.
I think the problem is that your buttons are only accessible in setScrollView.
so when a button tapped, in #Anton answer, just the clicked button is known in the didTap function.
I think that a better idea is to make an array of UIButtons,
initiate them in setScrollView,
and then use #Anton didTap function
class yourClass {
var buttons : [UIButton] = Array(repeatElement(UIButton(), count: 10))
override func viewDidLoad() {
super.viewDidLoad()
setUpScrollView()
// Do any additional setup after loading the view, typically from a nib.
}
func setUpScrollView() {
let buttonPadding:CGFloat = 10
var xOffset:CGFloat = 10
for i in 0...9 {
buttons[i].tag = i
buttons[i].backgroundColor = UIColor.red
buttons[i].setTitle("\(i)", for: .normal)
//Other functionality that you had set here before...
}
#objc func didTap(clickedButton: UIButton) {
for eachButton in self.buttons {
if eachButton.tag == clickedButton.tag {
eachButton.layer.borderColor = UIColor.white.cgColor
} else {
eachButton.layer.borderColor = UIColor.balck.cgColor
}
}
currentTag = clickedButton.tag
}
}
try this code
var allButtons = [UIButton]()
override func viewDidLoad() {
super.viewDidLoad()
setUpScrollView()
// Do any additional setup after loading the view, typically from a nib.
}
func setUpScrollView() {
let buttonPadding:CGFloat = 10
var xOffset:CGFloat = 10
for i in 0 ... 10 {
let button = UIButton()
button.tag = i
button.backgroundColor = UIColor.red
button.layer.borderWidth = 1.0
button.setTitle("\(i)", for: .normal)
button.addTarget(self, action: #selector(didTap), for: UIControlEvents.touchUpInside)
button.frame = CGRect(x: xOffset, y: CGFloat(buttonPadding), width: 70, height: 30)
xOffset = xOffset + CGFloat(buttonPadding) + button.frame.size.width;
scrollView.addSubview(button)
allButtons.append(button)
}
scrollView.contentSize = CGSize(width: xOffset, height: scrollView.frame.height)
}
#objc func didTap(button: UIButton) {
print("tap touch",button.tag)
allButtons.forEach { inButton in
if inButton == button {
button.layer.borderColor = UIColor.black.cgColor
} else {
button.layer.borderColor = UIColor.white.cgColor
}
}
currentTag = button.tag
}

How to call / access a label in button action programmatically?

//This is the label
let changeLbl = UILabel(frame: CGRect(x: 20, y: 170, width: 300, height: 21))
self.view.addSubview(changeLbl)
//This is the button
let submitButton = UIButton(type: .system) // let preferred over var here
submitButton.addTarget(self, action: #selector(buttonAction) , for: UIControlEvents.touchUpInside)
self.view.addSubview(submitButton)
//and this is action of above button
func buttonAction(sender: UIButton!) {
}
I want to call the above label in the following button function? like
func buttonAction(sender: UIButton!) {
changeLbl.ishidden = true
// want to access label here, but it's not working this way.
}
If you want to Access changeLbl you need to define as instance variable like this way and give global scope inside the class.
class ViewController: UIViewController {
var changeLbl : UILabel!
var submitButton : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
//This is the UILabel
changeLbl = UILabel(frame: CGRect(x: 20, y: 170, width: 300, height: 21))
self.view.addSubview(changeLbl)
//This is the button
submitButton = UIButton(type: .system) // let preferred over var here
submitButton.addTarget(self, action: #selector(buttonAction) , for: UIControlEvents.touchUpInside)
self.view.addSubview(submitButton)
}
//and this is action of above button
func buttonAction(sender: UIButton!) {
changeLbl.isHidden = true
}
}
changeLbl is a local variable. It's only visible in the scope of the method where the label is created.
If you don't want to use an instance variable – which is the normal way – and there is only one UILabel you can get the label from the subviews array
func buttonAction(sender: UIButton) {
if let changeLbl = self.view.subviews.filter({ $0 is UILabel}).first {
changeLbl.ishidden = true
}
}
If You want access label then declare it Globally.
Below Code for that:
class LabelDemo: UIViewController{
var changeLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
changeLbl = UILabel(frame: CGRect(x: 20, y: 170, width: 300, height: 21))
changeLbl.backgroundColor = UIColor.black
self.view.addSubview(changeLbl)
//This is the button
let submitButton = UIButton(type: .system) // let preferred over var here
submitButton.backgroundColor = UIColor.green
submitButton.frame = CGRect(x: 50, y: 150, width: 50, height: 30)
submitButton.setTitle("hide", for: .normal)
submitButton.addTarget(self, action: #selector(buttonAction) , for: UIControlEvents.touchUpInside)
self.view.addSubview(submitButton)
}
func buttonAction(sender: UIButton!) {
if changeLbl.isHidden {
changeLbl.isHidden = false
}else{
changeLbl.isHidden = true
}
}
}

Swift error with adding target

Here is my code. I get an unrecognized selector sent to instance crash/error every time I tap addButton. I've looked for the past hour for an answer and can't find one. Please help.
#IBOutlet var addButton: UIButton!
#IBOutlet var resetButton: UIButton!
var number:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
let size: CGSize = self.view.frame.size;
countLabel.frame = CGRect(x: 0, y:0, width: size.width, height: size.height/4)
minusButton.frame = CGRect(x:0, y: size.height/4, width: size.width/2, height: size.height/8);
addButton.frame = CGRect(x:0, y:size.height/4 + size.height/8, width: size.width, height: 5*size.height/8)
resetButton.frame = CGRect(x:size.width/2, y: size.height/4, width: size.width/2 ,height: size.height/8)
addButton.addTarget(self, action: #selector(addNumber(sender:)), for: UIControlEvents.touchUpInside)
minusButton.addTarget(self, action: #selector(minusNumber), for: UIControlEvents.touchUpInside)
resetButton.addTarget(self, action: #selector(resetNumber), for: UIControlEvents.touchUpInside)
}
func addNumber(sender: UIButton!) {
number = number + 1
countLabel.text = String(number)
}
Change
addButton.addTarget(self, action: #selector(addNumber(sender:)), for: UIControlEvents.touchUpInside)
With
addButton.addTarget(self, action: #selector(addNumber), for: UIControlEvents.touchUpInside)
You don't need to include sender in a selector.
So you need to change your code to
addButton.addTarget(self, action: #selector(addNumber), for: .touchUpInside).
And you don't need to implicitly unwrap sender
func addNumber(sender: UIButton)
Add #objc keyword before selector declaration:
#objc func addNumber(sender: UIButton!) {
number = number + 1
countLabel.text = String(number)
}

Resources