a newbie question :)
I'm trying to use Twiiter Digits for authentication (by phone number) in my (first) iOS app.
It is easier for my to understand how to position a button programatically when it is a button that i create. but this 1 line of code confuses me.
to embed their action button i just need to add this part of code (see documentation):
override func viewDidLoad() {
let digitsButton = DGTAuthenticateButton(authenticationCompletion: { (session, error) in
// Inspect session/error objects
})
self.view.addSubview(digitsButton)
}
My problem is that the creation of this button is automatically and have a completion handler, so when\where exactly do i have the option to position (format) it?
Thanks.
You can always create your own custom button and use the methods of Digits to perform the same actions. For example :
func didTapButton(sender: AnyObject) {
let digits = Digits.sharedInstance()
digits.authenticateWithCompletion { (session, error) in
// Inspect session/error objects
}
}
Also if you want to continue to customize your Digits button and it's View Controllers , you can find more here here.
It might sound strange but it took me some time to realize i can\need to do it after the completion handler (inside the ViewDidLoad...).
Thanks for Letting me know i can use my own button with Digits.
Related
I have a custom keyboard extension which works as expected but I am coming across some odd behaviour which I can't explain. It is designed primarily for data input into Excel spreadsheets, so the fewer the keystrokes the better.
I have 2 IBActions.
Keypressed takes the value of the keypresses and inserts it into the current cell.
Returnpressed emulates the enter key which moves the cursor onto the next cell.
These work as described above, which is all good, but I am now trying to combine the actions, so that the user only has to press the first key and it inserts the text and then moves onto the next cell.
So when I simply extend the code in the Keypressed IBAction to include the code in the Returnpressed action, it simply inserts a carriage return into the text and stays in the same cell.
What am I missing please?
Here is a code snippet:
extension UIKeyInput{
func `return`() -> Void{
insertText("\n")
}
}
class KeyboardViewController: UIInputViewController, AVAudioPlayerDelegate {
#IBAction func KeyPressed(_ sender: Any) {
let string = (sender as AnyObject).titleLabel??.text
(textDocumentProxy as UIKeyInput).insertText("\(string!)")
**//THIS IS THE LINE THAT FIXED THIS FOR ME
textDocumentProxy.adjustTextPosition(byCharacterOffset: -1)**
self.EnterPressed(nil)
}
#IBAction func EnterPressed(_ sender: Any?) {
//default action for a return key press
textDocumentProxy.return()
}
I think you need to override the UITextInputDelegate textDidChange method (UIInputViewController implements UITextInputDelegate).It turns out that textDidChange is called when the text changes. And make the first responder to the next text field of your cell.
I managed to fudge this by determining what action s caused textDidChange to fire. It turns out that by simply adjusting the cursor portion, between inserting the text and firing the Return action works.
Not really sure how, but achieves what I want without the the user knowing it is a kludge and no overhead. I have changed the original code snippet to show the fix.
Initially I had two buttons with titles: "+" and "-". Both buttons are located in table cell. I have used protocol and delegate to pass value from button title to function call which depends on input params. If input parameter is "-" - decrease value, if "+" - increase.
But later I removed titles and replaced buttons with respective images. And here I faced an issue - I cannot call function properly because title is blank.
I have implemented the following workaround. I have set Accessibility Identifier for both buttons. For example for +:
And in cell class I used accessibilityIdentifier:
#IBAction func didPressOrderCellButton(_ sender: UIButton) {
cellDelegate?.didPressOrderCellButton(order: order!, menuItem: menuItem!, action: sender.accessibilityIdentifier!)
}
But... I have some doubts if it's proper way to do this. Will it create any issues in future if I decide to work with accessibility feature?
I do not want to use title and add code to ViewController class to hide it every time view is loaded or appeared. I want to avoid such solutions in my code because it's too difficult to support such solutions I believe.
I have tried to find another button identifier that I can use, but didn't succeed.
The simple approach would be just set the tag value inside your button and then check the same tag value and perform your operation Plus or Minus accordingly.
For instance:-
if sender.tag == 0 {
//Do minus
} else if sender.tag == 1 {
//Do plus
}
all this is probably a trivial question, but I have not found a solution to it. I am making an app for Iphone using Swift.
I have a tableview with some strings and if I press a button I want to navigate back to the previous view directly. However, the code after my call
navigationController?.popViewControllerAnimated(true)
is always run, but I want the current activity to stop and go back to the previous view.
The code looks like:
#IBAction func DeletePressed(sender: UIButton) {
let deleteIndices = getIndexToDelete()
navigationController?.popViewControllerAnimated(true)
print("After navigationController")
for index in deleteIndices{
results?.ListResults[yearShownIndex].months[monthShownIndex].day[dayShownIndex].results.removeAtIndex(index)
}
if (results?.ListResults[yearShownIndex].months[monthShownIndex].day[dayShownIndex].results.count == 0){
results?.ListResults[yearShownIndex].months[monthShownIndex].day.removeAtIndex(dayShownIndex)
}
if (results?.ListResults[yearShownIndex].months[monthShownIndex].day.count == 0){
results?.ListResults[yearShownIndex].months.removeAtIndex(monthShownIndex)
}
if (results?.ListResults[yearShownIndex].months.count == 0){
results?.ListResults.removeAtIndex(monthShownIndex)
}
loadView()
}
"After navigationController" is always displayed.
In android you would start a new activity by creating intents to get the desired behaviour, but how does it work on Iphone?
My problem is that I want to be able to go back directly when navigationController.popViewControllerAnimated is called. This is just a toy example to understand how it works so that I can use it in the if-clauses later.
you could simply add a return statement after you pop the viewcontroller:
#IBAction func DeletePressed(sender: UIButton) {
let deleteIndices = getIndexToDelete()
navigationController?.popViewControllerAnimated(true)
return;
[...]
if you don't wants to execute code after "print("After navigationController")" then remove that code
or it is not possible to remove then toggle it when DeletePressed called
I am having a real challenge within one of my Swift iOS projects that I just don't seem to be able to find a solution for. I was hoping that someone can both recreate my issue and maybe make suggestions as to a resolution or workaround.
To summarize my issue:
I have 2 view controllers within a storyboard. The first view controller contains 3 buttons and the second view controller simply contains an image view. I created a segue on the first button of the first view controller to the second view controller and when I click the button, it works perfectly.
For my second button, I call the segue programmatically. First I assigned the segue an ID (MySegue) within the properties inspector, and then using a method within my view controller, I call the segue. When I click the second button, it works perfectly.
#IBAction func doSegue(sender: AnyObject) {
self.performSegueWithIdentifier("MySegue", sender: nil)
}
For my third button, I wanted to obtain some web data, and only upon success perform the segue. I am making use of NSURLSession to get the data with the completion handler performing the segue. My issue however is that when I click the third button, the Image View will not display no matter what I try. If I add buttons, labels or anything else, they display fine but not images. Here is my code for the button:
#IBAction func doNSURLSession(sender: AnyObject) {
let requestURL: NSURL = NSURL(string: "https://www.google.com")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
if error == nil {
NSLog("Success!")
self.performSegueWithIdentifier("MySegue", sender: nil)
} else {
NSLog("Fail")
}
}
task.resume()
}
I have tried everything I possibly can to work around this issue. I can perform the segue programmatically within a method and it works fine however if I call this segue, or even call a method which calls this segue from the completion handler of the web request, the image view does not show. Does anyone have any ideas as to what I'm either doing wrong, or anywhere I could look?
I have tried this both in XCode6 and the XCode 7 BETA, both have the same result too...
Thanks in advance for any help.
Regards,
Jon
The dataTaskWithRequest completion handler does not execute on the main thread.
Try calling performSegueWithIdentifier on the main thread:
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("MySegue", sender: nil)
}
I've browsed through many q&a-s here but almost all of them are way too specific for the use cases of other people.
My situation is more general and sort of simple:
iOS\Swift
I have a button which when clicked - moves the user to the next view.
At the same time as the button is clicked it also executes a query to Parse to fetch the data which will be displayed on the next view.
I'm using Parse's async query.getObjectInBackgroundWithId("jjjkkkdddd")
So if my code runs as is = click -> move to the next view -> empty
because fetching stuff takes a second or so.
What i want is to have a small animation popping up when user clicks a button to tell them that the data is being fetched at the moment and move to the next view once data arrives.
Here is my button tap code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "1") {
var svc = segue.destinationViewController as ViewControllerQuotes;
svc.toPass = functionToFetchDataFromParse() //<- takes longer than
//switching to the next view
//toPass is a var which lands into the next view
//and it's value is displayed to the user.
}
}
I am quite fresh with Swift and iOS dev so I can't figure this one out still:(
On the button tap just use addSubview() to add a UI element like UIActivityIndicatorView.
In the callback from Parse, remove the view and go to the next controller, calling the segue programatically.
SOLUTION FOR ME:
Ok i fiddled around and found the best way which suites me for now. what I do is from View1 the button is pressed and it tell the view controller of the 2-nd view to fire up the data fetching function.
In the 2-nd vie controller once it trigger the async function for retrieving data from Parse it also shows the activity indicator and make it run.
The user sees an empty screen with an activity spinner running. once the async function gets back the data it pushes it into a an empty label and shutsdown+hides the activity indicator.
Works great for my case. no interface hanging. and clear for the user about what's happening where and when.
Thanks to everyone!
p.s. this works for me because that's the end of the lifecycle for the retrieved data. if there were other functions depending on it - this wouldn't work:(
What about setting the object on the segue's destination View controller and then fetch the object, and then reload the view?
This would be:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "1") {
var svc = segue.destinationViewController as ViewControllerQuotes;
svc.yourObjectWhichIsToFetch = yourObjectWhichYouWantToPass //need to create a variable on the ViewControllerQuotes!
}
}
And then in the ViewControllerQuotes class:
class ViewControllerQuotes:ViewController {
var yourObjectWhichIsToFetch:PFObject?
override func viewDidLoad(){
super.viewDidLoad()
yourObjectWhichIsToFetch.fetchInBackgroundWithBlock({
(object, error) -> Void in
if error == nil {
//update the UI
}
})
}
}
With this code, you don't need to show any loading note (what is really ugly).