How to remove a button when it is clicked? - ios

I'm very new to swift. I've created multiple textfield and button by using subview. The output of my ViewController is below:-
Now I need to remove "-" button and it's corresponding textfield when it is clicked.
But I'm not able to detect which button is being clicked.
This is my code:
var y: CGFloat = 190
var by: CGFloat = 192
#IBAction func addRow(sender: AnyObject) {
y += 30
by += 30
let textFiled = UITextField(frame:CGRectMake(50.0, y, 100.0, 20.0))
textFiled.borderStyle = UITextBorderStyle.Line
let dunamicButton = UIButton(frame:CGRectMake(155.0, by, 15.0, 15.0))
dunamicButton.backgroundColor = UIColor.clearColor()
dunamicButton.layer.cornerRadius = 5
dunamicButton.layer.borderWidth = 1
dunamicButton.layer.borderColor = UIColor.blackColor().CGColor
dunamicButton.backgroundColor = .grayColor()
dunamicButton.setTitle("-", forState: .Normal)
dunamicButton.addTarget(self, action: #selector(removeRow), forControlEvents: .TouchUpInside)
self.view.addSubview(textFiled)
self.view.addSubview(dunamicButton)
}
func removeRow(sender: UIButton!) {
print("Button tapped")
self.view.removeFromSuperview()
}
any help would be appreciated...

eMKA was right! Try this:
import UIKit
class ViewController: UIViewController {
var y:CGFloat = 100
var textFields = [UIButton : UITextField]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func onAddMoreButtonPressed(sender: AnyObject) {
let newButton = UIButton(frame: CGRect(x: 50, y: y, width: 150, height: 20))
newButton.setTitle("New button", forState: .Normal)
newButton.backgroundColor = UIColor.blueColor()
newButton.addTarget(self, action: #selector(ViewController.onNewButtonPressed(_:)), forControlEvents: .TouchUpInside)
self.view.addSubview(newButton)
let newTextField = UITextField(frame: CGRect(x: 200, y: y, width: 150, height: 20))
newTextField.text = "New text field"
self.view.addSubview(newTextField)
textFields[newButton] = newTextField
y += 20
if y > self.view.frame.height {
y = 100
}
}
func onNewButtonPressed(sender: UIButton) {
textFields[sender]?.removeFromSuperview()
sender.removeFromSuperview()
}
}

You can override the method touchesBegan in any view controller. Assuming that you are storing an array of your buttons somewhere
let buttons : [UIButton] = []
you can do the following:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
guard let touch: UITouch = touches.first else {
return
}
for button in buttons {
if touch.view == button {
print("This is the button you tapped")
button.removeFromSuperview()
}
}
}

Related

Can a UIView assign a UITapGestureRecognizer to itself?

I'm trying to make a UIView that recognizes tap gestures, however taps are not ever correctly registered by the UIView. Here's the code for the UIView subclass itself:
import UIKit
class ActionCell: SignalTableCell, UIGestureRecognizerDelegate {
var icon: UIImageView!
var actionType: UILabel!
var actionTitle: UILabel!
var a:Action?
var tap:UITapGestureRecognizer?
required init(frame: CGRect) {
//
super.init(frame:frame)
tap = UITapGestureRecognizer(target: self, action: #selector(self.touchTapped(_:)))
tap?.delegate = self
addGestureRecognizer(tap!)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
tap = UITapGestureRecognizer(target: self, action: #selector(self.touchTapped(_:)))
tap?.delegate = self
addGestureRecognizer(tap!)
}
#objc func touchTapped(_ sender: UITapGestureRecognizer) {
print("OK")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.isUserInteractionEnabled = true
}
override func layoutSubviews() {
if(icon == nil) {
let rect = CGRect(origin: CGPoint(x: 10,y :20), size: CGSize(width: 64, height: 64))
icon = UIImageView(frame: rect)
addSubview(icon)
}
icon.image = UIImage(named:(a?.icon)!)
if(actionType == nil) {
let rect = CGRect(origin: CGPoint(x: 100,y :20), size: CGSize(width: 200, height: 16))
actionType = UILabel(frame: rect)
addSubview(actionType)
}
actionType.text = a.type
if(actionTitle == nil) {
let rect = CGRect(origin: CGPoint(x: 100,y :80), size: CGSize(width: 200, height: 16))
actionTitle = UILabel(frame: rect)
addSubview(actionTitle)
}
actionTitle.text = a?.title
}
func configure( a:Action ) {
self.a = a
}
override func setData( type:SignalData ) {
a = (type as! Action)
}
}
I'm simply trying to make it so that this UIView can, you know, know when it's tapped. Is this possible without adding a separate UIViewController? This seems as though it should be fairly simple but it doesn't appear to be, confusingly.
I've stepped through the code and the init method is called and the Gesture Recognizer is added but it doesn't trigger.
If its a table view cell, I'd recommend not using a tap gesture, since it might interfere with the didSelectRowAtIndexPath: and other delegate methods. But if you still wanna keep the tap gesture, try adding tap?.cancelsTouchesInView = false before addGestureRecognizer(tap!) and see if that works.
If you just want to know when its tapped, you could also override the following UIResponder method:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
// do your stuff
}
I think, it is easier to override touchesBegan method. Something like this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touched")
super.touchesBegan(touches, with: event)
}
Most likely the actionType, ActionTitle, and icon are being tapped and the tap is not falling through because user interaction is disabled by default for labels and images. Set isUserInteractionEnabled = true for each of those fields that are subviews of the main view.
override func layoutSubviews() {
if(icon == nil) {
let rect = CGRect(origin: CGPoint(x: 10,y :20), size: CGSize(width: 64, height: 64))
icon = UIImageView(frame: rect)
icon.isUserInteractionEnabled = true
addSubview(icon)
}
icon.image = UIImage(named:(a?.icon)!)
if(actionType == nil) {
let rect = CGRect(origin: CGPoint(x: 100,y :20), size: CGSize(width: 200, height: 16))
actionType = UILabel(frame: rect)
actionType.isUserInteractionEnabled = true
addSubview(actionType)
}
actionType.text = a.type
if(actionTitle == nil) {
let rect = CGRect(origin: CGPoint(x: 100,y :80), size: CGSize(width: 200, height: 16))
actionTitle = UILabel(frame: rect)
actionTitle.isUserInteractionEnabled = true
addSubview(actionTitle)
}
actionTitle.text = a?.title
}

Swift Radio Buttons Not Clickable

I am using the DLRadioButton library through Cocoa Pods found here
Below is my code, essentially the radio buttons appear however I am only able to click 1 of them in the group and I am unsure why. Note that I am populating the Radio Buttons based on an Int in Firebase that indicates how many to populate:
` override func viewDidLoad() {
super.viewDidLoad()
ref = FIRDatabase.database().reference()
pollRef = ref.child("Polls").child(pass)
passLabel.text = pass
pollImage.sd_setImage(with: URL(string: passedImageURL), placeholderImage: UIImage(named: "test"))
pollRef.observe(FIRDataEventType.value, with: {(snapshot) in
self.numberOfChildren = Int(snapshot.childSnapshot(forPath: "answers").childrenCount)
self.passLabel.text = String(self.numberOfChildren)
print(self.numberOfChildren)
var buttons = [DLRadioButton]()
for x in 0..<self.numberOfChildren {
let answerLabel = snapshot.childSnapshot(forPath:
"answers").childSnapshot(forPath:
String(x+1)).childSnapshot(forPath: "answer").value
let firstRadioButton = self.createRadioButton(frame: CGRect(x:
CGFloat(x)*32, y:self.view.center.y , width: 40.0, height: 20.0),
title: answerLabel as! String, color: UIColor.black)
// firstRadioButton.translatesAutore sizingMaskIntoConstraints = false
let screenSize: CGRect = UIScreen.main.bounds
firstRadioButton.frame = CGRect(x: 0, y: 0, width: 50, height: screenSize.height * 0.2)
firstRadioButton.tag = x
buttons.append(firstRadioButton)
self.view.addSubview(firstRadioButton);
}
let groupButtons = DLRadioButton()
groupButtons.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(groupButtons)
let margins = self.view.layoutMarginsGuide
groupButtons.bottomAnchor.constraint(equalTo: margins.bottomAnchor, constant: 0).isActive = true
groupButtons.otherButtons = buttons
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> DLRadioButton {
let radioButton = DLRadioButton(frame: frame);
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: UIControlState.normal);
radioButton.setTitleColor(color, for: UIControlState.normal);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
radioButton.addTarget(self, action: #selector(self.logSelectedButton(_:)), for: UIControlEvents.touchUpInside);
return radioButton;
}
#IBAction func logSelectedButton(_ radioButton: DLRadioButton) {
if radioButton.isMultipleSelectionEnabled {
for button: DLRadioButton in radioButton.selected() {
print("\(button.titleLabel?.text) is selected.\n")
}
}
else {
print("\(radioButton.selected()?.titleLabel?.text) is selected.\n")
}
}
`
You need to selector method of button
let firstRadioButton = self.createRadioButton(frame: CGRect(x: self.view.center.x, y: CGFloat(x)*32, width: 100.0, height: 120.0), title: answerLabel as! String, color: UIColor.green)
firstRadioButton.tag = x
firstRadioButton.addTarget(self, action: #selector(self.logSelectedButton), for: .touchUpInside)
buttons.append(firstRadioButton)
Selector method : you can change as per needs
#IBAction func logSelectedButton(_ radioButton: DLRadioButton) {
if radioButton.isMultipleSelectionEnabled {
for button: DLRadioButton in radioButton.selectedButtons {
print("\(button.titleLabel?.text) is selected.\n")
}
}
else {
print("\(radioButton.selectedButton.titleLabel?.text) is selected.\n")
}
}

Creating buttons with a for loop? Swift

func makeAButton(){
var tag = 1
for post in postArray {
let cgX = CGFloat(post.x!)
let cgY = CGFloat(post.y!)
let button : DragImg = DragImg(frame: CGRect(x: cgX, y: cgY, width: 100, height: 100))
button.backgroundColor = UIColor.blueColor()
button.setTitle(post.user, forState: .Normal)
button.addTarget(self, action: #selector(self.buttonAction), forControlEvents: .TouchUpInside)
button.tag = tag
self.view.addSubview(button)
print(tag)
tag += 1
}
}
I've currently got 7 things in my post array, and when I print out the tag, I get the
1
2
3
... and so on up to 7.
Whats happening though is that at the 0th item in the aray, 1 button is being created. Then at the 1st, 2 are being created at that x/y, and it keeps going up and up until I'm getting 7 buttons right ontop of eachother.
Why is this the case? I thought here the for loop would say:
For each post in PostArray make a single button using the data from that item in the PostArray.
How might I change this to work as intended?
Edit: (Just posting everything I've got)
import UIKit
import Firebase
class testController: UIViewController {
#IBOutlet weak var button : UIButton!
#IBOutlet weak var textField: UITextField!
var colorsArray = [String]()
var currentX = CGFloat()
var currentY = CGFloat()
var postArray = [CirclePost]()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
let position :CGPoint = touch.locationInView(view)
currentY = position.y
currentX = position.x
}
}
override func viewDidLoad() {
super.viewDidLoad()
DataService.ds.REF_BASE.child("Colors").observeEventType(.Value) { (snapshot: FIRDataSnapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
self.postArray = []
for snap in snapshots {
if let x = snap.value!["x"] as? CGFloat, y = snap.value!["y"] as? CGFloat, color = snap.value!["color"] as? String {
let post = CirclePost(postKey: snap.key, user: color , x: x, y: y)
self.postArray.append(post)
print(self.postArray.count)
self.makeAButton()
}
}
}
}
}
func makeAButton(){
var tag = 1
for post in postArray {
let cgX = CGFloat(post.x!)
let cgY = CGFloat(post.y!)
// let button = DragImg()
let button : DragImg = DragImg(frame: CGRect(x: cgX, y: cgY, width: 100, height: 100))
button.backgroundColor = UIColor.blueColor()
button.setTitle(post.user, forState: .Normal)
button.addTarget(self, action: #selector(self.buttonAction), forControlEvents: .TouchUpInside)
button.tag = tag
self.view.addSubview(button)
tag += 1
}
}
func buttonAction(sender: UIButton!) {
let button = postArray[sender.tag - 1]
print(button.user)
print("Button tapped")
}
#IBAction func buttonPressed(sender: AnyObject) {
let ref = DataService.ds.REF_BASE.child("Colors").childByAutoId()
ref.child("color").setValue(textField.text)
ref.child("x").setValue(currentX)
ref.child("y").setValue(currentY)
}
}
Here's your issue:
for snap in snapshots {
...
self.postArray.append(post)
print(self.postArray.count)
self.makeAButton()
You're adding a post to the array, then drawing the array (1 item). Then next time you add an additional post and then draw the array (2 items) and so on.
You need to move the call self.makeAButton() out of that for loop.

How can I make empty circle on baseball out count?

I am making baseball outcount code based on FoodTracker source code. Here's my code but empty circle doesn't count in this code. How can I make the empty circle rating? I would appreciate if you guys can help me out. Thank you!!
///////
import UIKit
class RatingControl: UIView {
// MARK: Properties
var rating = 0 {
didSet {
setNeedsLayout()
}
}
var ratingButtons = [UIButton]()
var spacing = 3
var circles = 3
// MARK: Initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let filledCircleImage = UIImage(named: "checkedRed")
let emptyCircleImage = UIImage(named: "UncheckedRed")
for _ in 0..<3 {
let button = UIButton()
button.setImage(emptyCircleImage, forState: .Normal)
button.setImage(filledCircleImage, forState: .Selected)
button.setImage(filledCircleImage, forState: [.Highlighted, .Selected])
button.adjustsImageWhenHighlighted = false
button.addTarget(self, action: "ratingButtonTapped:", forControlEvents: .TouchDown)
ratingButtons += [button]
addSubview(button)
}
}
override func layoutSubviews() {
// Set the button's width and height to a square the size of the frame's height.
let buttonSize = Int(frame.size.height)
var buttonFrame = CGRect(x: 0, y: 0, width: buttonSize, height: buttonSize)
// Offset each button's origin by the length of the button plus spacing.
for (index, button) in ratingButtons.enumerate() {
buttonFrame.origin.x = CGFloat(index * (buttonSize + spacing))
button.frame = buttonFrame
}
updateButtonSelectionStates()
}
override func intrinsicContentSize() -> CGSize {
let buttonSize = Int(frame.size.height)
let width = (buttonSize + spacing) * circles
return CGSize(width: width, height: buttonSize)
}
// MARK: Button Action
func ratingButtonTapped(button: UIButton) {
rating = ratingButtons.indexOf(button)! + 1
updateButtonSelectionStates()
}
func updateButtonSelectionStates() {
for (index, button) in ratingButtons.enumerate() {
// If the index of a button is less than the rating, that button should be selected.
button.selected = index < rating
}
}
}
if you want zero to count then return 0 as a possible button action. Your rating is already set to zero so technically it does count. If you accidentally tap the first circle and want to undo it you can try something like this in ratingButtonTapped
//rating = ratingButtons.index(of: button)! + 1
rating = (rating == 1) && (ratingButtons.index(of: button) == 0) ? 0 : (ratingButtons.index(of: button)! + 1)

Button stops moving when creating new button who moves

I'm creating a game where a button who is being created moves from one side of the screen to the other when I click a button called start. The problem is that when I click start before the button who was moving reaches its end point, it stops instead of continuing (and the another created button start moving like expected).
Should I create a new CADisplayLink every time I click the start button? If so, how would I do that? Here's the code:
var button1 = UIButton()
var displayLink: CADisplayLink?
var startTime: CFAbsoluteTime?
let duration = 2.0
var leadingConstraint: NSLayoutConstraint!
var topConstraint: NSLayoutConstraint!
var l1 = false
#IBAction func start(sender: UIButton) {
n1()
}
func n1() {
l1 = false
startTime = CFAbsoluteTimeGetCurrent()
displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
}
func handleDisplayLink(displayLink: CADisplayLink) {
if l1 == false { // so it doesn't randomize leading constraint twice
button1 = createButton()
let randomNumber = Int(arc4random_uniform(180) + 30)
let elapsed = CFAbsoluteTimeGetCurrent() - startTime!
var percentComplete = CGFloat(elapsed / duration)
if percentComplete >= 1.0 {
percentComplete = 1.0
// self.button1.removeFromSuperview()
displayLink.invalidate()
button1.hidden = true
}
leadingConstraint.constant = CGFloat(randomNumber)
topConstraint.constant = 390 - 350 * percentComplete
NSLayoutConstraint.activateConstraints([
leadingConstraint,
topConstraint,
button1.widthAnchor.constraintEqualToConstant(75),
button1.heightAnchor.constraintEqualToConstant(75)
])
l1 = true
}
else{
let elapsed = CFAbsoluteTimeGetCurrent() - startTime!
var percentComplete = CGFloat(elapsed / duration)
if percentComplete >= 1.0 {
percentComplete = 1.0
displayLink.invalidate()
button1.hidden = true
}
topConstraint.constant = 390 - 350 * percentComplete
NSLayoutConstraint.activateConstraints([
leadingConstraint,
topConstraint,
button1.widthAnchor.constraintEqualToConstant(75),
button1.heightAnchor.constraintEqualToConstant(75)
])
}
}
func buttonPressed(sender: UIButton!) {
button1.hidden = true
displayLink?.invalidate()
}
func createButton() ->UIButton {
let button = UIButton()
button.setImage(UIImage(named: "BlueBall.png")!, forState: UIControlState.Normal)
button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
leadingConstraint = button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant: 0)
topConstraint = button.topAnchor.constraintEqualToAnchor(view.topAnchor, constant: 0)
NSLayoutConstraint.activateConstraints([
leadingConstraint,
topConstraint,
button.widthAnchor.constraintEqualToConstant(75),
button.heightAnchor.constraintEqualToConstant(75)
])
return button
}
Please help. It would be really appreciated. Thanks in advance. Anton
Okay Anton O; as discussed I post an answer how to detect a touch on a moving UIView. This works for both, CAAnimation and UIView.animationWith..
First I created an extension of CGRect, just for convenience:
extension CGRect {
init(position: CGPoint, size: CGSize) {
self.origin = CGPoint(x: position.x - (size.width / 2.0), y: position.y - (size.height / 2.0))
self.size = size
}
}
Then I created two methods which create and move the view. You can adapt the code then to your needs. (I hold a global variable called nextView to keep reference to the view, can also be extended to an array of course)
Create View:
private func createView(index: Int) {
nextView?.removeFromSuperview()
nextView = UIView()
nextView?.bounds = CGRect(x: 0, y: 0, width: 60, height: 60)
nextView?.backgroundColor = UIColor.redColor()
nextView?.center = CGPoint(x: 30, y: CGRectGetMidY(self.view.bounds))
if let nextView = nextView {
view.addSubview(nextView)
}
}
Move View:
private func moveView() {
guard let nextView = nextView else {
return
}
UIView.animateWithDuration(5.0) { () -> Void in
nextView.center = CGPoint(x: CGRectGetMaxX(self.view.bounds) + 30, y: CGRectGetMidY(self.view.bounds))
}
}
Detect Touch:
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
if let touch = touches.first, nextView = nextView {
let touchRect = CGRect(position: touch.locationInView(self.view), size: CGSize(width: 20, height: 20))
guard let viewPosition = nextView.layer.presentationLayer()?.position else {
return
}
let viewRect = CGRect(position: viewPosition, size: nextView.bounds.size)
if CGRectIntersectsRect(touchRect, viewRect) {
print("👍 💯")
} else {
print("👎")
}
}
}
You can extend the methods for your needs and also add some "performance" enhancing checks (like if a view is visible and move on or return right there in the touchesEnded method, etc.)

Resources