how to detect when user click lyft Button swift - ios

We want Lyft button touch event because I am working in analytics, so, I need how many people choose Lyft but I can't put UIView click event. I try below code.
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.checkAction))
cell.lyftButton.addGestureRecognizer(gesture)
How can i achieve this?

You can directly assign a selector method to lyftButton e.g
lyftButton.addTarget(self, action: #selector(lyftButtonAction(_:)), for: .touchUpInside)
#objc
func lyftButtonAction(_sender: UIButton) {
//Do your action
}

To retrieve the LyftButton, you'll need to fetch the button inside the Lyft view, after retrieving it, I tried to add another target to it which was your 'checkAction' method, but for some reason it is not being called. One workaround solution is:
On Auto Layout, created a transparent button on top of the Lyft Button View, let's callet it 'Transparent Lyft Button': Example (I've embeded in another view because it was on a stackView);
On the code, retrieved the button with the above method, held it in a variable, let's call it 'requestLyftButton' and disabled it.
Created an IBAction for the 'Transparent Lyft Button' that triggers the method 'self.checkAction' that you've created and also calls requestLyftButton.sendActions(for: .touchUpInside), which triggers the original Lyft SDK action.
To Retrieve Lyft UIButton:
#IBOutlet weak var lyftButton: LyftButton!
#IBOutlet weak var transparentLyftButton: UIButton!
var requestLyftButton: UIButton?
func retrieveLyftButton(in view: UIView) {
for view in view.subviews {
if let lyftBtn = view as? UIButton {
lyftBtn.isEnabled = false
requestLyftButton = lyftBtn
} else {
retrieveLyftBtn(in: view)
}
}
}
transparentLyftButton IBAction to trigger your method + lyft sdk original action:
#IBAction func requestLyft(_ sender: UIButton) {
if let lyftBtn = requestLyftButton {
checkAction() // Your method
lyftBtn.sendActions(for: .touchUpInside)
}
}
I hope that you can understand what was done, if you have any questions, just let me know.

Related

How to write unit test for button tap?

Here I'm trying to check unit test cases for view controller.
- I have a view controller with button and label.
- When you click on the button, it will call another method. which feeds the data to the button action label text change.
- I want to check that button triggered that method or not? without adding any boolean or return type of the function.
Here is my code.
class ViewController: UIViewController {
#IBOutlet weak var buttonFetch: UIButton?
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func fetchUser() {
self.nameLabel.text = self.getUser()
}
func getUser() ->String {
return User.data()
}
}
struct User {
static func data()->String{
return "Apple"
}
}
Here is my test case
func testFetchUserAction() {
controller.buttonFetch?.sendActions(for: .touchDown)
// I want to test the method getUser from viewcontroller gets called or not
// some thing like this XCTAssert(self.controller.getUser(),"not called")
XCTAssertEqual(self.controller.nameLabel.text!, "Apple")
}
Have you tried as like below..
func testFetchUserAction() {
self.controller.nameLabel.text = nil
//Use this line, If you assigned touchUpInside to your button action
controller.buttonFetch?.sendActions(for: .touchUpInside)
//Use this line, If you assigned touchDown to your button action
controller.buttonFetch?.sendActions(for: .touchDown)
XCTAssert(self.controller.nameLabel.text != nil, "not called")
}
Note: To make test case failed purposely, you can change UIControl.Event in sendActions
What you're missing:
Make sure to call loadViewIfNeeded() somewhere.
This can be in the test, or in setUp(). This will load your outlets, and call viewDidLoad().
Then, as much as possible, test the result of invoking an action, instead of whether or not a method was called. You've done this in your example assertion.
I'd also add that the correct action for buttons is almost always .touchUpInside, not .touchDown. This allows the user to press a button, then drag away to change their mind. "I don't want to push this after all."
Found something similar on another response, attempted something like this?
Source: How to add tap action for button in "Unit Testing" and show Alert
func testTappingLoginButton_ShouldPresentAlert() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sut = storyboard.instantiateInitialViewController() as! ViewController
sut.loadViewIfNeeded()
let alertVerifier = QCOMockAlertVerifier()
sut.loginButton.sendActions(for: .touchUpInside)
XCTAssertEqual(alertVerifier.presentedCount, 1)
}
Let me know if it works or not!
I have tried like below, its passed the test.
But I'm not sure it is correct or not?
XCTAssertNotNil(self.controller!.getUser, "get user method not called")
Fake tap action on a button for UIViewController testing.
By using this helper, tap(_:), you can verify if your button perform the
#IBAction you were expecting when testing your ViewController.
public func tap(_ button: UIButton) {
button.sendActions(for: .touchUpInside)
}
// Button in your UIViewController
#IBOutlet weak var primaryButton: UIButton!
// In your XCTest subclass
var sut: UIViewController!
tap(sut.primaryButton) // example of use in your test() function

Programmatically Tap View

I have created a custom view that is to be used as a radio button with images and text. I need to be able to load the saved selection when the controller loads. I set my listeners this way:
for button in genderButtons {
button.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(genderTapped(_:))))
}
#objc private func genderTapped(_ sender: UITapGestureRecognizer) {
for button in genderButtons {
button.select(sender.view! == button) // Toggles the button to display selected/deslected state.
...
}
}
The problem is that I can't find a way to tell the view to select. I tried making the gesture recognizer and object, but it doesn't have any methods I can use to trigger it. The 'buttons' aren't actually buttons, they're views, so I can't send an action event.
How can I select the correct button with code?
Just call genderTapped directly, handing it the gesture recognizer already attached to the desired "button".
For example, if thisGenderButton is the one you want to "tap", say:
if let tap = thisGenderButton.gestureRecognizers?[0] as? UITapGestureRecognizer {
genderTapped(tap)
}
You can add this method in your customView like this,
Class CustomView: UIView {
public func select(_ value: Bool) {
self.backgroundColor = value ? .green: .red
}
}
and then in below method you can call select for the tapped view.
#objc private func genderTapped(_ sender: UITapGestureRecognizer) {
(sender.view as? CustomView)?.select(true)
}

Swift custom button class

I'm trying to create a custom class that creates a button. I'm having trouble adding a target to that button inside it's class. This is my code
class SelectButton{
var button:UIButton = UIButton()
init(button_frame: CGRect, button_title: String, connected: [UIButton]?){
self.button.frame = button_frame
self.button.setTitle(button_title, for: UIControlState.normal)
self.button.addTarget(self, action:#selector(self.buttonPressed), for: .touchUpInside)
}
func construct() -> UIButton {
return self.button
}
#objc func buttonPressed() {
print("Button Clicked")
}
}
The problem is that I can't connect an action on button click. This works if it's used outside my class but not inside.
Usage of the class
let test = SelectButton(button_frame: CGRect(x:50, y:50, width: 250, height:150), button_title: "Test button", connected: nil).construct()
self.view.addSubview(test)
When someone taps the button, usually you want something to happen somewhere else in your app (like in one of your view controllers or in some other UI element). The way the IBAction is set up right now, you have it so that something will trigger or happen within the button itself when someone taps on it. If you want to handle a button tap programmatically instead of ctrl dragging from the button into the view controller, you can do it this way if you prefer. First, add this code into the view controller:
#IBAction func buttonPressed(sender: UIButton) {
}
Then you can either add the selector programmatically by adding this method into your view controller:
myButton.addTarget(self, action:self.buttonPressed(sender), for: .touchUpInside)
Or by going to the connections inspector and dragging from the touch up inside over to the IBAction dot in your view controller code. Also, as someone else pointed out in the comments you should make your button inherit from UIButton by adding this to your class declaration:
class SelectButton: UIButton {
. . .
}
Nothing is holding a strong reference to your SelectButton instance, so as soon as the function that creates test exits, that instance is released.
The button itself is retained because you have added it as a subview. Therefore, it is still visible but there is no longer an object to respond to the action.
You either need to use an instance property rather than a local variable for test, or, preferably have SelectButton inherit directly from UIButton

Action not available for UISwitch

I created a UISwitch on storyboard and tried to drag it to controller to create an action but there were only Insert Outlet / Insert Outlet Collection 2 options available? Why did this happen and how can I create action for UISwitch? I am using Xcode8.1
PS: The UISwitch was added on a container view
When "ctrl" + drag, you should see something like:
You should choose "Action" and let the event -which is by default- "Value Changed".
However, if you can't see this (and I assume you should, or there is somehow a problem), you can add an event programmatically to the switch outlet:
In viewDidLoad() method, you need to add:
override func viewDidLoad() {
// ...
mySwitch.addTarget(self, action: #selector(mySwitchTapped), for: .valueChanged)
// ...
}
mySwitchTapped(mySwitch: UISwitch) method:
func mySwitchTapped(mySwitch: UISwitch) {
if mySwitch.isOn {
} else {
}
}

Having a button add text to a UITextField in swift

I am creating a post to twitter app and want to add various text to the UITextField from buttons that can be selected. The UIButton are for various hashtags to speed the process of writing a tweet. I have tried a couple the solutions found on Stack but none seem to work and they are all in Objective-C.
Screenshot of compose tweet view before buttons touched.
http://postimg.org/image/5qoyk6673/
Screenshot of compose tweet view after button selected and text added to text field.
http://postimg.org/image/vp08wsa6b/fa7c7a83/
class TweetComposeViewControler: UIViewController, UITextViewDelegate {
var selectedAccount : ACAccount!
#IBOutlet var tweetContent: UITextView!
#IBAction func specializedButton(sender: UIButton) {
tweetContent.text = sender as UIButton
tweetContent.text.stringByAppendingString(specializedButton(titleLabel.text))
}
func insertHashtag(sender: UIButton!) {
tweetContent.text = tweetContent.text.stringByAppendingString(sender.titleLabel.text)
}
You can set the UITextFields text to the title of your UIButton:
txtField.text = hashTagButton.titleLabel.text
And if you want to append the text:
txtField.text = textField.text.stringByAppendingString(hashTagButton.titleLabel.text)
In order to have your buttons update the text upon pressing them you need to add a target selector for when the buttons are pressed. This can be done via Storyboard or programmatically.
Programmatically
You would add the same selector to all buttons using this:
hashtagButton.addTarget(self, action: Selector("insertHashtag:"), forControlEvents: .TouchUpInside)
This will call the insertHashtag function whenever the hashtagButton is pressed. Because of the : at the end of the selector, it will also pass itself as a parameter so you can use it to get the button's title rather than creating a different selector for each button.
func insertHashtag(sender: UIButton!) {
txtField.text = textField.text.stringByAppendingString(sender.titleLabel!.text)
}
Using IBAction
#IBAction func insertHashtag(sender: AnyObject) {
txtField.text = sender as UIButton
textField.text.stringByAppendingString(btn.titleLabel!.text)
}
Here you cast the sender paramter as a UIButton since you know a UIButton is the type of the object which called it.
If you know that only UIButton's will cause this method you can do this:
#IBAction func insertHashtag(btn: UIButton ) {
txtField.text = sender as UIButton
textField.text.stringByAppendingString(btn.titleLabel!.text)
}
Response to your update
The code you added needs to be fixed to look like this:
#IBAction func specializedButton(sender: UIButton) {
tweetContent.text.stringByAppendingString(sender.titleLabel!.text)
}
Here sender is your UIButton and you pass it as a UIButton so you do not need to convert it.

Resources