How to remove multiple buttons that I created with a loop? - ios

EXPLANATION:
1) I initiate the button above the class :
var myButton = UIButton()
2) I then create x amount of buttons depending on how many items are in an array
for letter in arrayOfLetters {
myButton = UIButton(frame: CGRect(x: buttonX, y: 500, width: someFloat, height: someFloat))
buttonX = buttonX + thirdFloat //spacing
myButton.layer.cornerRadius = 5
myButton.backgroundColor = UIColor.darkGrayColor()
myButton.setTitle("\(letter)", forState: UIControlState.Normal)
myButton.titleLabel?.text = "\(letter)"
myButton.addTarget(self, action: "myButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(myButton)
}
3) Later on once the user has pressed the correct buttons, I call a function to refresh and I want to remove all buttons. This is so I can generate new buttons based on new array
myButton.removeFromSuperview()
ISSUE:
However this does nothing, I tried giving the buttons a tag and deleting buttons by tag == tagId but nothing happened.
I can delete all views but it deletes everything else,
I tried this but again nothing happends
var buttons = [myButton]
for button in buttons as! [UIButton] {
button.removeFromSuperview()
}
I want to delete all buttons I added and i'm either not deleting them or deleting everything in the view

EASY FIX:
1) Inside Class, out of any func:
var buttonsArray = [UIButton]()
2) Declare myButton here and add the append line:
for letter in arrayOfLetters {
var myButton = UIButton(frame: CGRect(x: buttonX, y: 500, width: someFloat, height: someFloat))
...
self.buttonsArray.append(myButton)
}
3) To remove buttons:
for btn in buttonsArray {
btn.removeFromSuperview()
}
EXPLANATION:
Always store in an array the elements you create with a loop if you want to easily remove all of them at once.

i hope it will help for you give tag for your button while you are adding delete that button
for button in self.view.subviews {
if button.tag == 100 {
button.removeFromSuperview()
}
}

you are re-assigning the myButton variable as you loop.
Remove this line:
var myButton = UIButton()
add a property at the top to hold the buttons:
var buttons:[UIButton]()
then later in your code:
for letter in arrayOfLetters {
var myButton = UIButton(frame: CGRect(x: buttonX, y: 500, width: someFloat, height: someFloat))
buttonX = buttonX + thirdFloat //spacing
myButton.layer.cornerRadius = 5
myButton.backgroundColor = UIColor.darkGrayColor()
myButton.setTitle("\(letter)", forState: UIControlState.Normal)
myButton.titleLabel?.text = "\(letter)"
myButton.addTarget(self, action: "myButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(myButton)
self.buttons.append(myButton)
}
Then you should be able to remove like so:
for button in self.buttons {
button.removeFromSuperview()
}
This should resolve your issue, But it's important to understand what the problem was, so you define a new button as a property with this line: var myButton = UIButton(). This holds ONE button. as you are looping through creating buttons you are overriding the button with the next one.
So if anything, Calling myButton.removeFromSuperView() will remove the last one you created. Doing it the way I suggested means you create a button and add it to an array of buttons, so later you can iterate over the array referencing each button in turn and remove it.

Related

Swift - UIButton created programatically doesn't trigger touch event

I have created a button programatically and want to add a touch event handler. I have tried all the tricks I have found online but the desired function is just never triggered.
upgradeNowView = UIButton()
upgradeNowView.setTitle("Upgrade", forState: .Normal)
upgradeNowView.contentMode = UIViewContentMode.ScaleToFill
upgradeNowView.frame = CGRect(x: upgradeNowView.frame.minX, y: -50 , width: 320, height: 50)
upgradeNowView.userInteractionEnabled = true
upgradeNowView.sendActionsForControlEvents(.TouchUpInside)
upgradeNowView.addTarget(self, action: #selector(MainViewContainer.upgradeTapped(_:)), forControlEvents: .TouchUpInside)
side_menu_controller?.view.addSubview(upgradeNowView)
and defined this
func upgradeTapped(sender: UIButton)
{
UpgradeViewController.openUpgrade()
}
But this just never gets called. Any help would be appreciated.
You need to define upgradeTapped function in class of side_menu_controller instance. I guess, it's SideMenuController class.
I found out this was caused by the fact that I was placing the button next to the view but outside its bounds (just on top):
upgradeNowView.frame = CGRect(x: upgradeNowView.frame.minX, y: -50 , width: 320, height: 50)
There are two ways around this:
Move the button inside the bounds of the parent view, or
Handle touches outside the view by overriding "hitTest" as discussed here

How to create an array of UITextField objects in Swift?

I am working on an application in Swift. At the beginning I provide number of inputs that I would like to add. In next view I create as many UITextFields as I defined in first view.I have a problem with storing of all this values from TextFields after pressing the button. It seems to me that the most effective solution is to create an array of UITextFields and add every value of TextField into array and then in action for button adding values which are in all TextFields into array. Unfortunately, it doesn't work. Any suggestions? Thanks in advance.
override func viewDidLoad() {
super.viewDidLoad()
var counter = 0
for i in 1...mainInstance.numberOfInputs
{
super.viewDidLoad()
array.insert(UITextField(frame: CGRect(x: 0, y: 50, width: 60, height: 20)), at: i)
array[i].center = CGPoint(x: 200,y: 50 + counter)
array[i].textAlignment = NSTextAlignment.center
array[i].layer.borderWidth = 1
array[i].layer.borderColor = UIColor.black.cgColor
self.outletScrollView.addSubview(array[i])
counter += 50
}
super.viewDidLoad()
let button = UIButton(type: .system) // let preferred over var here
button.frame = CGRect(x: 200, y: 50 + counter, width: 100, height: 20)
button.setTitle("Recalculate", for: UIControlState.normal)
button.addTarget(self, action: "actionRecalculate:", for: UIControlEvents.touchUpInside)
self.outletScrollView.addSubview(button)
outletScrollView.contentInset = UIEdgeInsetsMake(0, 0, CGFloat(counter+100), 0)
}
You could create easily with:
let textFields = [UITextField]()
You should consider using an UIScrollView, (like in your example) or (better idea in my opinon) a UITableView to add your UITextfields. So you have multiple Rows, and every row has one UITextField. The number of rows / Textfield can u easily customize (and get it from your FirstViewController for example).
Just create a custom UITableViewCell - add an UITextField and connect the IBOutlet. To get the values from every UITextField you could iterate through all cells, and read out the values. Just ask, if you need more help about doing that.
Creating array of UITextfield could be done this way
// Create an empty array of type UITextField
var listOfTextFields : [UITextField] = []
// In viewDidLoad, create a textfield and add it to the array
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...mainInstance.numberOfInputs-1 {
let textField = UITextField((frame: CGRect(x: X, y: Y*i, width: yourWidth, height: yourHeight)))
textField.delegate = self
listOfTextFields.append(textField)
}
}
In this UITextField setup, I didn't account for any formatting to shorten the answer.
Though this might not be for the exact use case, it could help others with similar use cases (particularly programmatically created textfields or custom uicell).
txtfield.tag = indexPath.row // or other int
Then you implement textfield didEndEditing after array has been initialized and delegating
#IBAction func endedEditing(_ sender: UITextField) {
arr[sender.tag] = sender.text
}

Add a dynamic part as subview in a view controller

I am trying to make a reusable PopUp view controller composed of the following:
a static part (the top one) with an image and a label
a dynamic part (lower one) that can contain either 1 large button, or 2 smaller one side by side or 2 smaller buttons on top of one another.
It should look like this:
For now here is what I did:
Created a PopUpViewController class
In the storyboard, added a VC with the PopUpViewController class
Added the outlets for the static part
And now, I don't know how to proceed.
The idea of showing/hiding objects depending on the style of the popup (1 or 2 buttons etc.) seems horrible to me.
I don't think I can use xibs ?
I wish I could use storyboards because I am unable to do the auto layout via code.
Is code still the way to go ?
You can create 3 buttons inside your code. And using an if statement either show the 2 small buttons or the big one. Otherwise i think u can add 2 "View" objects in your storyboard and add 2 buttons in one and 1 button on the other and show and hide the "View" you want again with an if statement.
Here is an example :
import UIKit
class ViewController: UIViewController {
var flag = false
var buttonSmallOne: UIButton!
var buttonSmallTwo: UIButton!
var buttonBigOne: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Create the 3 buttons
buttonSmallOne = UIButton(frame: CGRect(x: self.view.bounds.width/2 - 50, y: self.view.bounds.height/2, width: 50, height: 50))
buttonSmallOne.backgroundColor = .green()
buttonSmallOne.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
buttonSmallTwo = UIButton(frame: CGRect(x: self.view.bounds.width/2 + 50, y: self.view.bounds.height/2, width: 50, height: 50))
buttonSmallTwo.backgroundColor = .green()
buttonSmallTwo.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(buttonSmallOne)
self.view.addSubview(buttonSmallTwo)
buttonBigOne = UIButton(frame: CGRect(x: self.view.bounds.width/2-100, y: self.view.bounds.height/2, width: 100, height: 50))
buttonBigOne.backgroundColor = .red()
buttonBigOne.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.view.addSubview(buttonBigOne)
buttonBigOne.isHidden = true
buttonBigOne.isEnabled = false
}
func buttonAction(sender: UIButton!) {
if flag == false {
// Hide
buttonSmallOne.isHidden = true
buttonSmallOne.isEnabled = false
buttonSmallTwo.isHidden = true
buttonSmallTwo.isEnabled = false
// Show
buttonBigOne.isHidden = false
buttonBigOne.isEnabled = true
flag = true
}else{
// Show
buttonSmallOne.isHidden = false
buttonSmallOne.isEnabled = true
buttonSmallTwo.isHidden = false
buttonSmallTwo.isEnabled = true
// Hide
buttonBigOne.isHidden = true
buttonBigOne.isEnabled = false
flag = false
}
}
}
I would advise you to create a class for the container (for the dynamic content).
Create one class with a stack view in it(you can change from horizontal to vertical, based on button logic ).
Create third class with button and label in it.
Construct the container with the right views based on Enum configuration.
Create everything from code and added this container subview to your popOver on creation.
If you have to support iOS 8 you can use this with reachability(check for ios version). It works great for this kind of problems. And later on you can just rename it and delete iOS 8 code from the project. It has the same API as a stackView.
https://github.com/tomvanzummeren/TZStackView

Change tint image color when pressing uibutton in Swift

I have a scrollview inside a view. Inside the scrollview I create programmatically 5 buttons. Every button loads a different image with a different tag each one. I added a function that is called when pressing the buttons.
let avatarsListScrollingView = avatarsListView(CGSizeMake(70.0, 55.0), avatarCount: 5)
func avatarsListView(buttonSize:CGSize, avatarCount:Int) -> UIView {
**CODE**
for i in 0...(avatarCount-1) {
let button = UIButton(type: .Custom)
**CODE**
button.setImage(UIImage(named: avatarsList[i]), forState: .Normal)
button.tag = i
button.addTarget(self, action: "avatarListSelected:", forControlEvents: .TouchUpInside)
avatarButtonView.addSubview(button)
}
return avatarButtonView
}
Then when pressing the buttons, I call to "avatarListSelected":
func avatarListSelected(sender:UIButton){
if let image = sender.imageView?.image?.imageWithRenderingMode(.AlwaysTemplate) {
sender.setImage(image, forState: .Normal)
sender.tintColor = UIColor.redColor()
}
self.addAvatarView.reloadInputViews()
}
This function tints the image button to red, it is working fine, but the problem is that when I press some other button, I want the other one goes to the original color. Right now every button that I press gets in red.
I tried to add the call to "self.addAvatarView.reloadInputViews()" to try to "redraw" again all the buttons, but never gets called.
Do you guys know some way to do this?
Thanks to everybody!
This is the final code that solved the problem:
func avatarListSelected(sender:UIButton){
print(sender.tag)
if let image = sender.imageView?.image?.imageWithRenderingMode(.AlwaysTemplate) {
sender.setImage(image, forState: .Normal)
sender.tintColor = UIColor.redColor()
}
for view in self.avatarButtonView.subviews as [UIView] {
if let btn = view as? UIButton {
if btn.tag != sender.tag {
btn.setImage(UIImage(named: avatarsList[btn.tag]), forState: .Normal)
}
}
}
}
Create a property selectedButton: UIButton? and keep a reference to the selected button there. Don't forget to update it in avatarListSelected method and before you change it, if it isn't nil, change its color to original (and then change it).
If the buttons have different original colors, subclass UIButton class and keep the original color there.
I don't know if is better approach or answer, but, i maybe could delivery this using this approach:
Create a method that will "fill" the color for your choice button and "clear" color to others , but its a method that loop through UIScrollView and look for each UIButton. Something like this :
func setBackgroundColorButton(color:UIColor , buttonTag:Int){
for view in self.scrollView.subviews as [UIView] {
if let btn = view as? UIButton {
if btn == buttonTag {
btn.tintColor = color
} else {
btn.tintColor = UIColor.whiteColor()
}
}
}
}
This is the concept, i didn't tested, but maybe just need adjust to search inside your scroll view or similar.
But with this will be work nice i believe :D
You could do it like this
for i in 0...5 {
let button = UIButton(type: .Custom)
let x = 50 * i + 10
let y = 50
button.frame = CGRectMake(CGFloat(x), CGFloat(y), 40, 40)
button.setTitle("\(i)", forState: .Normal)
button.tag = i
button.backgroundColor = UIColor.greenColor()
button.tintColor = UIColor.blueColor()
button.addTarget(self, action: "avatarListSelected:", forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
func avatarListSelected(sender : UIButton){
sender.backgroundColor = UIColor.orangeColor()
for view in self.view.subviews{
if(view.isKindOfClass(UIButton)){
let button = view as! UIButton
if button.tag != sender.tag{
button.backgroundColor = UIColor.greenColor()
}
}
}
}
The frame etc is just for demonstation purpose only, you should of course use your own value. The tintColor property is not valid for all button types. Read the documentation for more information.

Insert a button and load a second view programmatically using Swift

I want to, programmatically, add a button to a view and then when the user press this button a second view called "Giraanam" is loaded. I managed to write the code to display the button, but I cannot discover how to make it load the second view... Can anyone please help me?
The code I tried so far is:
let button = UIButton.buttonWithType(UIButtonType.System) as UIButton
button.frame = CGRectMake(20, 25, 34, 34)
button.backgroundColor = UIColor.greenColor()
button.setBackgroundImage(UIImage(named:"Back_Resultados.png"),forState: UIControlState.Normal)
button.addTarget(self, action: "Giraanam", forControlEvents: UIControlEvents.TouchUpInside)
self.addSubview(button)
You need to implement function Giraanam to create a new view and add to another view. Example:
func Giraanam() {
let newView = UIView()
// customise your view
self.view.addSubview(newView)
}

Resources