addTarget not working for UIButton created in Swift - ios

So, I've created a UIButton using Swift, and I animate it and it's superview using the following code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//create a UIView to contain buttons. Set background color to nil, so it's transparent.
var controlsView = UIView(frame: CGRect(x:0, y:0, width:400, height:400));
controlsView.alpha = 1.0
controlsView.backgroundColor = nil
//create a button and add some attributes. Self explanatory
var loginButton: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
loginButton.frame = CGRectMake(20.0, 40.0, 200, 60)
loginButton.alpha = 0.0
loginButton.setTitle("Login", forState: .Normal)
loginButton.titleColorForState(.Normal)
loginButton.layer.cornerRadius = 20;
loginButton.layer.borderWidth = 1.0
loginButton.layer.borderColor = CGColorCreate(CGColorSpaceCreateDeviceRGB(), [0.827, 0.325, 0.0, 1.0])
loginButton.addTarget(self, action: "loginPressed:", forControlEvents: .TouchUpInside)
//add the button to the view created to hold it
controlsView.addSubview(loginButton)
//now test blurring the background view. Create a UIVisualEffectView to create the blur effect. New in iOS7/8
/*
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = self.introImage.bounds
self.introImage.addSubview(visualEffectView)
visualEffectView.alpha = 0.0
*/
//add the controls subview to the image view already here.
self.introImage.addSubview(controlsView)
//loginButton.addTarget(self, action: "loginButtonWasPressed:",forControlEvents:.TouchUpInside)
UIView.animateWithDuration(0.7,
animations: {
loginButton.alpha = 1.0
loginButton.frame = CGRect(x: 20.0, y: 100.0, width: 200, height: 60)
//visualEffectView.alpha = 0.5
},
completion:nil)
}
That's working fine. Then I created a function which should be called on touchUpInside of the button I created above:
#IBAction func loginPressed(sender:UIButton){
var alertView = UIAlertView();
alertView.addButtonWithTitle("Ok");
alertView.title = "title";
alertView.message = "message";
alertView.show();
}
When I touch the button, the function DOES NOT fire. Can anyone help? I'm testing this on an actual device (iPhone 6 Plus/iOS 8.1.1

To add an action to a button, you need to use the following code
loginButton.addTarget(self,action:#selector(loginPressed),
forControlEvents:.TouchUpInside)
This code is working fine for me.
For more detail you can follow this [Attach parameter to button.addTarget action in Swift
Thanks.

Related

Is this a good way to show a view by touch a button at the middle of the navigation bar and remove it by touch anywhere else?

I'm trying to put a button at the middle of the navigation bar, it will show a list when I touch it (I added a pure UIView here instead of a UITabeView to just make the code simpler) . And then the additional view will be removed when I touch anywhere else. So I add a background view whose size is the same as the screen to response my touch. Although it still behind the navigation bar.
Here is my question:
Is this a good implementation?
class ViewController: UIViewController {
var optionView: UIView!
var backgroundView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(ViewController.titleButtonTapped), for: .touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: 20, height: 30)
button.backgroundColor = .red
navigationItem.titleView = button
}
func titleButtonTapped() {
backgroundView = UIView(frame: UIScreen.main.bounds)
backgroundView.backgroundColor = .clear
let gesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleGesture)) // add this gesture to response my touch
backgroundView.addGestureRecognizer(gesture)
view.addSubview(maskView)
optionView = UIView(frame: CGRect(x: -40, y: 30, width: 100, height: 100)) // x = button.wdith / 2 - optionView.width / 2
optionView.backgroundColor = .red
navigationItem.titleView?.addSubview(alertView)
}
func handleGesture() {
optionView.removeFromSuperview()
backgroundView.removeFromSuperview()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Now it looks like the following.
Edit:
The following is my implementation of a popover view.
func buttonTapped() {
let popoverViewController = UIViewController()
popoverViewController.preferredContentSize = CGSize(width: 300, height: 300)
popoverViewController.modalPresentationStyle = .popover
let presentationController = popoverViewController.popoverPresentationController!
presentationController.delegate = self
presentationController.sourceView = view
presentationController.sourceRect = CGRect(x: 100, y: 100 , width: 100, height: 100)
present(popoverViewController, animated: true, completion: nil)
}
// delegate
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
It's a little bit different frrom the Apple documentation. They recommended that we'd better configure the presentation controller after calling present(:animated: completion:) method. But it doesn't work if I don't configure it before presentation. Maybe, because I set the delegate.
Configuring the popover presentation controller after calling present(_:animated:completion:) might seem counter-intuitive but UIKit does not create a presentation controller until after you initiate a presentation. In addition, UIKit must wait until the next update cycle to display new content onscreen anyway. That delay gives you time to configure the presentation controller for your popover.
For using a popover or not, it depends on the purpose of this pop over view. If it has lots of information, it will be better to separate it out to another view controller and make segue to it on button click. This will provides user the full screen to look at whatever it is.
For me, adding a button at the center of a navigation bar is not usual. You have to inform me about it for me to click on it.
In conclusion:
If you want a popover view to tell user hints or show them something, it will be better to use UIPopoverPresentationController so that you don't need to care about the styles.
If you want another view to show data, list of pictures etc, it will be better to use a segmented control or another view controller
var optionView: UIView!
var backgroundView: UIView!
override func viewDidLoad()
{
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
let button = UIButton(type: .system)
button.addTarget(self, action: #selector(ViewController.titleButtonTapped), for: .touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: 20, height: 30)
button.backgroundColor = .red
navigationItem.titleView = button
}
func titleButtonTapped()
{
if backgroundView == nil
{
backgroundView = UIView(frame: UIScreen.main.bounds)
backgroundView.backgroundColor = .clear
let gesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleGesture)) // add this gesture to response my touch
backgroundView.addGestureRecognizer(gesture)
view.addSubview(backgroundView)
}
if optionView == nil
{
optionView = UIView(frame: CGRect(x: -40, y: 30, width: 100, height: 100)) // x = button.wdith / 2 - optionView.width / 2
optionView.backgroundColor = .red
navigationItem.titleView?.addSubview(optionView)
}
}
func handleGesture()
{
if optionView != nil
{
optionView.removeFromSuperview()
optionView = nil
}
if backgroundView != nil
{
backgroundView.removeFromSuperview()
backgroundView = nil
}
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}

Xcode 7.3.1 : Set background image to UINavigationBar and display back button

I want to set logo of app as background image to UINavigationBar and when user traverse into app it should display logo as well as back button on top of it.
Below is code that I've used :
func setNavigationBar() {
let navigationBarHeight: CGFloat = self.navigationController!.navigationBar.frame.height
let screenSize: CGRect = UIScreen.mainScreen().bounds
let objCustomView = CustomView(frame: CGRect(x: 0, y: 0, width: screenSize.width, height: navigationBarHeight))
let objWindow = UIApplication.sharedApplication().keyWindow
objWindow?.addSubview(objCustomView)
self.navigationItem.setHidesBackButton(false, animated:true);
self.navigationItem.backBarButtonItem = UIBarButtonItem(title:"", style:.Plain, target:nil, action:nil)
}
The issue with this is that back button goes behind the image.
How to fix this?
After refering post by #NDoc I'm getting extra space in left. Why so?
Also, the back button should be white with no back text i.e. only < arrow.
Below is code for customView :
class CustomView: UIView {
var imgLogo = UIImageView(frame:CGRectZero)
override init(frame: CGRect) {
super.init(frame: frame)
let screenSize: CGRect = UIScreen.mainScreen().bounds
imgLogo.frame = CGRectMake(0, 0, screenSize.width, 44.0)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
imgLogo.image = UIImage(named:"BoM_Logo")
self.addSubview(imgLogo)
}
}
You can display your logo in leftBarButtonItem and set the leftItemsSupplementBackButton to true to display backButton also like this.
let logoView = UIImageView(frame: CGRect(x: 0, y: 0, width: 60, height: 30))
logoView.image = UIImage(named: "Logo")
let item = UIBarButtonItem(customView: logoView)
self.navigationItem.leftBarButtonItem = item
To show the back button with your logo image set leftItemsSupplementBackButton to true
self.navigationItem.leftItemsSupplementBackButton = true
Edit:
If you want custom arrow then you need to use leftBarButtonItems and pass array of BarButtonItem and no need to set leftItemsSupplementBackButton to true like this.
let logoView = UIImageView(frame: CGRect(x: 0, y: 0, width: 60, height: 30))
logoView.image = UIImage(named: "Logo")
let logoItem = UIBarButtonItem(customView: logoView)
let btnBack = UIButton(frame: CGRect(x: 0, y: 0, width: 25, height: 25))
btnBack.setImage(UIImage(named: "Back_Arrow"), forState: .Normal)
btnBack.addTarget(self, action: #selector(self.buttonAction(_:)), forControlEvents: .TouchUpInside)
let backItem = UIBarButtonItem(customView: btnBack)
self.navigationItem.leftBarButtonItems = [backItem, logoItem]
Note: Don't forgot to add buttonAction action method inside your viewController.
Try this in your appDelegate
let image = UIImage.init(named:"upper-bar.png")
UINavigationBar.appearance().setBackgroundImage(image,forBarMetrics:UIBarMetrics.Default)
for back button try this in the viewDidLoad() of your viewController
let image1 = UIImage(named: "go10.png") as UIImage?
let btnLeft = UIButton(type: .Custom)
btnLeft.frame = CGRectMake(0, 0, 25, 25)
btnLeft.setImage(image1,forState:UIControlState.Normal)
btnLeft.addTarget(self, action:(#selector(NameofyourViewController.backBtn(_:))),forControlEvents:UIControlEvents.TouchUpInside)
let leftBarButton = UIBarButtonItem(customView: btnLeft)
self.navigationItem.leftBarButtonItem = leftBarButton
#IBAction func backBtn(sender: UIButton)
{
self.navigationController?.popViewControllerAnimated(true)
}

how to dismiss a UIView when tapped outside its bounds?

I have a View Controller that has a main view, inside that i have created a small drop down(a pop up menu) towards the right that is also a UIView. I have added a button that shows and dismisses this pop up menu view when tapped.
All is working fine.
But now I want it to dismiss the view when the user taps outside those bounds.
The current code is as follows
var vw = UIView()
func popup(){
vw = UIView(frame: CGRectMake(self.view.frame.size.width - 210, 20, 260, 320))
vw.backgroundColor = UIColor.whiteColor()
vw.layer.cornerRadius = 5.0
vw.layer.shadowColor = UIColor.blackColor().CGColor
vw.layer.shadowOpacity = 0.8
vw.layer.shadowRadius = 3.0
vw.layer.shadowOffset = CGSizeMake(2.0, 2.0)
let name: UILabel = UILabel(frame: CGRectMake(5, 0, 90, 30))
name.text = testUserName
name.font = UIFont(name: "Abc Lt", size: 20.0)
let orgName: UILabel = UILabel(frame: CGRectMake(5, 35, 90, 30))
orgName.text = "Abc Lt"
name.font = UIFont(name: "V Lt", size: 25.0)
let profileImageView: UIImageView = UIImageView(frame: CGRectMake(137, 4, 35, 35))
profileImageView.image = UIImage(named: "profilepic.png")
let dropUpButton: UIButton = UIButton(frame: CGRectMake(profileImageView.frame.origin.x + 42, 18, 15, 10))
// dropUpButton.imageView.image = [UIImage imageNamed:#"dropdown.png"];
dropUpButton.setImage(UIImage(named: "dropup.png"), forState: .Normal)
dropUpButton.addTarget(self, action: #selector(LandingPageViewController.hideView), forControlEvents: .TouchUpInside)
vw.addSubview(name)
vw.addSubview(orgName)
vw.addSubview(profileImageView)
vw.addSubview(dropUpButton)
self.drawLine()
let tableView: UITableView = UITableView(frame: CGRectMake(0, 70, vw.frame.size.width, vw.frame.size.height-40), style: .Plain)
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
tableView.scrollEnabled = false
vw.addSubview(tableView)
self.navigationController!.view!.addSubview(vw)
}
//the function that displays and dismiss the pop up menu
func hideView() {
vw.hidden = true
}
I have read some posts where one can use a tap gesture to find where it's tapped, and based on that using an if/else condition it can be solved but I am not sure.
Also you can check the image that I have uploaded for better understanding:
What you can really do is to take main superview full size same as your screen size. give clear background to it.Take a contentview same as you are doing now. Add a button similar size to super view and on click selector you can remove view from superview.
There are also alternative ways for doing this by identifying touch location. But It takes lots of effort.
Hope this helps you.
You can use tap gesture to do that
add this code on main view:
let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:)))
tap.delegate = self
self.view.addGestureRecognizer(tap)
and then
func handleTap(sender: UITapGestureRecognizer? = nil)
{
hideView()
}

Selector method of UIButton not called during animation

I have dynamically created buttons on a dynamic view and later I add that dynamic view to main view.
Everything is working well except that the selector method of UIButton is not called.
var baseView:UIView?
override func viewDidLoad() {
super.viewDidLoad()
randomizeButtons()}
func randomizeButtons(){
baseView = UIView(frame:CGRectMake(view.bounds.origin.x + 10, view.bounds.origin.y + 50, view.bounds.size.width, view.bounds.size.height-20))
let viewWidth = baseView.bounds.size.width;
let viewHeight = baseView.bounds.size.height;
baseView.userInteractionEnabled = true
let i = GlobalArrayofUsers.count
var loopCount = 0
while loopCount < i{
let userBaseView = UIView(frame: CGRectMake(abs(CGFloat(arc4random()) % viewWidth - 90) , abs(CGFloat(arc4random()) % viewHeight - 120), 90, 90))
print(userBaseView.frame)
userBaseView.backgroundColor = UIColor.redColor()
userBaseView.userInteractionEnabled = true
userBaseView.layer.cornerRadius = 45
userBaseView.clipsToBounds = true
let button = UIButton(frame: userBaseView.bounds)
button.backgroundColor = UIColor.greenColor()
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: #selector(ViewController.handleTapEventofBtn(_:)), forControlEvents: .TouchUpInside)
button.setTitle("hello", forState: .Normal)
button.userInteractionEnabled = true
userBaseView.addSubview(button)
baseView.addSubview(userBaseView)
print("button frame is\(button.frame)")
baseView.bringSubviewToFront(userBaseView)
loopCount += 1
}
}
baseView.subviews.forEach { (users) in
UIView.animateWithDuration(1, delay: 0, options: [.Autoreverse,.Repeat], animations: {
users.center.y += 10
}, completion: nil)
}
view.insertSubview(baseView, atIndex: view.subviews.count)
}
func handleTapEventofBtn(sender: UIButton!) {
// handling code
}
Any idea why my selector method is not called? It is due to animation. How can i handle it.
SOLUTION: Allow userinteraction in UIAnimationOptions
The problem is that you are trying to click an object that is being animated. From the docs:
During an animation, user interactions are temporarily disabled for
the views being animated. (Prior to iOS 5, user interactions are
disabled for the entire application.)
But worry not, the solution is very easy, just call your animation with the option .AllowUserInteraction. For example (with your code):
UIView.animateWithDuration(1, delay: 0, options: [.Autoreverse,.Repeat,.AllowUserInteraction], animations: {
users.center.y += 10
}, completion: nil)
Have you tried this way:
for _ in 0...5{
// generate new view
let userBaseView = UIView(frame: CGRectMake(abs(CGFloat(arc4random()) % viewWidth - 90) , abs(CGFloat(arc4random()) % viewHeight - 120), 90, 90))
userBaseView.backgroundColor = UIColor.redColor()
// add button to view
let button = UIButton(frame: userBaseView.bounds)
button.backgroundColor = UIColor.yellowColor()
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: #selector(self.handleTapEventofBtn(_:)), forControlEvents: .TouchUpInside)
button.setTitle("hello", forState: .Normal)
userBaseView.addSubview(button)
}
self.view.addSubview(userBaseView)
All you need is to create userBaseView before cycle, then create buttons in cycle and add them to userBaseView, after that just add userBaseView to self.view or where you need to add it. In your example you create userBaseView in every iteration of the loop.
I think the problem could be here:
userBaseView.addSubview(button)
// add new view containing button to self.view
self.view.addSubview(userBaseView)
}
userBaseView.addSubview(button)
baseView.addSubview(userBaseView)
First you add userBaseView to self.view in the loop:
// add new view containing button to self.view
self.view.addSubview(userBaseView)
then add it to baseView:
baseView.addSubview(userBaseView)
Can you post how it looks like in IB?
The action has a parameter so the selector signature is actually takeActionBtn:
(note the colon at the end).
You need to change that or the button will try to call a version of the function with no parameter which doesn't exist.
button.addTarget(self, action: "button:",forControlEvents: UIControlEvents.TouchUpInside)
func button(sender: UIButton!) {
// handling code
print("1")
}
// hi. your problem is in the selector line. try this:
for _ in 0...5 {
// generate new view
let userBaseView = UIView(frame: CGRectMake(abs(CGFloat(arc4random()) % self.view.frame.size.width - 90) , abs(CGFloat(arc4random()) % self.view.frame.size.height - 120), 90, 90))
userBaseView.backgroundColor = UIColor.redColor()
// add button to view
let button = UIButton(frame: userBaseView.bounds)
button.backgroundColor = UIColor.yellowColor()
button.showsTouchWhenHighlighted = true
button.addTarget(self, action: "buttonAction", forControlEvents: UIControlEvents.TouchUpInside)
button.setTitle("hello", forState: .Normal)
userBaseView.addSubview(button)
self.view.addSubview(userBaseView)
}
// tested with xcode 7.2
func buttonAction() {
print("working")
}

exc_bad_access on uibutton click using Xcode 6 and Swift language

I am trying to add another sub view on click of button.
First view is created using storyboard and button action is working fine.
But when I add new viewcontroller's view as subview and click on button, application crashes with exc_bad_access on iPhone Simulator.
here is the code:
override func viewDidLoad() {
super.viewDidLoad()
let datePick : UIDatePicker = UIDatePicker(frame: CGRectMake(0, 0, 218, 216))
datePick.backgroundColor = UIColor.whiteColor()
datePick.layer.borderColor = UIColor.blackColor().CGColor
datePick.layer.borderWidth = 5
let actionView : UIView = UIView(frame: CGRectMake(0, 216, datePick.frame.width, 50))
actionView.backgroundColor = UIColor.blackColor()
self.view.addSubview(datePick)
var cancelButton : UIButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
cancelButton.frame = CGRectMake(datePick.frame.width-80, 5, 60, 40)
cancelButton.setTitle("Cancel", forState: UIControlState.Normal)
cancelButton.backgroundColor = UIColor.redColor()
cancelButton.addTarget(self, action: "cancelPressed:", forControlEvents: UIControlEvents.TouchUpInside)
actionView.addSubview(cancelButton)
var doneButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
doneButton.frame = CGRectMake(20, 5, 60, 40)
doneButton.backgroundColor = UIColor.greenColor()
doneButton.setTitle("Done", forState: .Normal)
doneButton.addTarget(self, action: "buttonAction:",forControlEvents:UIControlEvents.TouchUpInside)
self.view.addSubview(actionView)
actionView.addSubview(doneButton)
// datePicker.frame = CGRectMake(0, 0, 218, 216);
// Do any additional setup after loading the view, typically from a nib.
}
func buttonAction(sender:UIButton!)
{
println("Button tapped")
}
func cancelPressed(sender: UIButton!) {
println("Cancel Clicked!!!")
}
IBAction Method called from first viewcontroller's view is :
#IBAction func dateSelectClicked (sender:AnyObject){
var datePicker = DatePicker()
datePicker.view.frame = CGRectMake(0, self.view.frame.height, self.view.frame.width, self.view.frame.height)
let isfinished : Bool = true
self.view.addSubview(datePicker.view)
UIView.animateWithDuration(0.5, delay: 1.0 , options: UIViewAnimationOptions.CurveEaseInOut, animations: { datePicker.view.frame = CGRectMake(0, self.view.frame.height-266, self.view.frame.width, self.view.frame.height)}, completion: {(isfinished) in println("finished")})
}
Change this 2 lines from:
self.view.addSubview(actionView)
actionView.addSubview(doneButton)
to:
actionView.addSubview(doneButton)
self.view.addSubview(actionView)
Finally I found the problem :
As provided in question, DatePicker viewcontroller was adding as :
var datePicker = DatePicker()
on click of button.(func dateSelectClicked)
So this is the problem with creating instance of DatePicker.
We need to create it as property outside method as :
Class firstViewController :UIViewController {
var datePicker = DatePicker()
}
and use as property in method self.datepicker

Resources