Prevent custom keyboard in textfield - iphone

I was experimenting with how a custom keyboard affects my app. I installed Swype on my iPhone 6.
I find that in some of my views where I have custom inputView property set on a text field, the Swype keyboard is overriding and presenting instead of my picker. This completely breaks my UI and cannot be allowed.
Is there a way to explicitly tell iOS 8 only to use the inputView I have set?
Is this a bug, perhaps? It is not at all expected behavior to allow a third party to override my input spec?

You can disable custom keyboard for your app with the following code:
include this in your app delegate:
- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(NSString *)extensionPointIdentifier {
if ([extensionPointIdentifier isEqualToString: UIApplicationKeyboardExtensionPointIdentifier]) {
return NO;
}
return YES;
}

Swift 4
func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplicationExtensionPointIdentifier) -> Bool {
if (extensionPointIdentifier == .keyboard) {
return false
}
return true
}

Using the answer from Pablo Ezequiel Romero as a starting point, I was able to get things to work for me. Essentially, rather than using a UIViewController for the custom keyboard, use a UIInputViewController and put your controls inside the UIInputViewController's inputView. Then, assign the inputView of your UITextField or UITextView to the inputView of the UIInputViewController.
If you're using auto layout, you need to make sure that you set everything properly and make sure to set an initial height constraint on the inputView and set its priority below the max 999 level (I used 800). Any height will do; the system will replace your constraint with one of its own. The lower priority avoids auto layout conflicts. (For me, if I didn't include this constraint, the final view wouldn't have any height at all.)
When I did all this, I was able to switch in and out of my (internal to the app) custom keyboard and any third-party keyboard extension.

I had a similar issue and I was able to fix it using UIInputViewController. Basically the view that I set in inputView is the view of my UIInputViewController subclass. I was using UIViewController, but after replacing the base view controller it started to work well.

To stop users from using custom keyboard extensions for individual fields, you can use SecureTextEntry in UIKit (SecureField in SwiftUI). Although these objects automatically mask user input without the option to change it (which makes them simple to use for passwords, not applicable for all kinds of secrets).
For example, the SwiftUI declaration looks as follows:
var passw: String = ""
(...)
SecureField("Password", text: $passw)
The first argument is a prompt that the user will see.
Note that SecureField will automatically block keyboard extension not only on its field but also on other fields on the same application screen (applies to TextField as well).

Related

Need to use a NSTextView (or NSTextField) for a clickable URL

I'm given an arbitrary NSAttributedString (parsed from markdown, not that it matters here) which may contain URLs that I want to be clickable in a text field within an NSTableView cell. The requirements state that if the user clicks the URL, they be taken to it with the default browser. IF they click anywhere else in the cell, we have default behavior (displaying an additional info popup).
I'm attempting to use a NSTextView to display the content. However, clicking outside the URL but within the view selects the text and eats the mouse click. Making the view not selectable won't allow clicking the URL either. I also don't really want the text to be selectable but that's a minor side problem.
So... I decided to make my view controller an NSTextViewDelegate so I could use some of those callbacks. But my app crashes if I set the NSTextView's delegate property to 'self'. This happens even if I don't implement any of the functions, even though they are all optional.
I'm using Swift 3 and wonder if there's some bug or other issue there? The call stack appears to be sending a textView:willChangeSelectionFromCharacterRanges:toCharacterRanges: message even though it's not implemented. And incidentally, implementing that method isn't helping either.
Any help, or sample code in Swift 3 using the delegate protocol, would be greatly appreciated.
Here's the crash I get by simply setting the delegate property on NSTextView:
By request, here's the code that set's the delegate. Currently I just set it whenever the message changes. This can obviously be optimized but for now I just want to see it work.
var notification: SSNotification! {
didSet {
guard let notificationCellView = self.view as? SSNotificationCellView else { return }
notificationCellView.subjectLabel.stringValue = notification.subject
if let description = notification.message , description != "" {
let attrString = TSMarkdownParser.standard().attributedString(fromMarkdown: description)
notificationCellView.messageLabel.textStorage?.setAttributedString(attrString)
notificationCellView.messageLabel.isHidden = false
notificationCellView.messageLabel.delegate = self
} else {
notificationCellView.messageLabel.isHidden = true
}
}
}
I never did figure out why I was crashing but I was able to come up with a workaround. I was originally trying to make the view controller for the table cell which contained NSTextView be the delegate. I changed it so that the cell's view subclass itself was the delegate and all is well.
I don't get it but it works, so that's what matters.

NSTextField: exposing its Copy and Paste methods

I am trying to access the copy, cut, and paste methods of a NSTextField instance in its window delegate so I can customize these methods. I find that unlike tableViews and textViews, the textfield's copy, paste and cut actions are not responsive in the delegate. My understanding is that all text controls share the window's field editor yet this does not seem to be the case.
I thought perhaps the TextField's field editor was not being shared with the window delegate, however I did some testing I see that as I am typing in control, those field editors are identical--very strange.
My current work-around is to use a subclass instance of NSTextView where the copy and paste action methods respond as needed. This, however, has its own issues and I was hoping there was some way to get NSTextFields to work as expected.
A nstextfield does not have copy and paste functions. Those are only found in nstextview. the catch is that when a textfield is edited it opens up a textview called a fieldeditor during the editing and sets that as the first responder.
How to solve:
Each text field has a cell as a child connected to it (called cell in the picture but should be named more appropriately, e.g. CustomTextEditor):
The cell has a method for implementing a custom field editor called fieldEditorForView:
class cell: NSTextFieldCell {
var editor: NSTextView
override func fieldEditorForView(aControlView: NSView) -> NSTextView? {
if editor == nil {
editor = ESPasteView()
}
return editor
}
}
This above function allows you to provide your own custom NSTextView subclass:
class ESPasteView: NSTextView, NSTextViewDelegate {
override func paste(sender: AnyObject?) {
Swift.print("user tries to paste")
super.pasteAsPlainText(nil)
}
}
Credit to:
How to disable context menus with right mouse click in an NSTextField (Cocoa)?
and Ken Thomases who pointed out the field editor.
Maybe you could take a look at NSTextField's:
- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard type:(NSString *)type;
- (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard type:(NSString *)type;
This would allow you to intercept the call customize the response.

xcode 4.2.1 - custom keyboard - two UITextFields

I have created a custom keyboard and I have two text fields.
I am calling [firstTextField becomeFirstResponder] in my viewDidLoad
to have my keyboard visible.
How can I know which text field is currently active so that I write what the user is typing from the keyboard to the respected textField?
I have tried - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField but it is not being called
any idea?
You should be able to use isFirstResponder to determine which of your two UITextFields is currently active.
if ([firstTextField isFirstResponder]) {
...
}
else {
...
}
To get textFieldShouldBeginEditing to be called, you need to set the delegate outlets for both your text fields to whatever view controller (or wherever) the textFieldShouldBeginEditing method lives in.
You can set the delegates programmatically (e.g. firstTextField.delegate = self;) or via the XIB file.
And your intuition is correct, once textFieldShouldBeginEditing gets called, you will know (from the textField parameter) which field the user is currently typing in.

why override canBecomeFirstResponder?

I'm looking at TVAnimationGestures from WWDC 2010, and in the TableVieWController.m, they override canBecomeFirstResponder:
- (BOOL)canBecomeFirstResponder {
return YES;
}
Is there a reason they do this? I don't see this method called anywhere. Thanks.
So you can mark your question as answered...
They are using an UIMenuController within the sample, and in order to receive messages from that controller to your controller, you must make your controller the first responder (and accept becoming first responder via canBecomeFirstResponder.
This method is called by the Cocoa framework and not typically application to see if a controller should become the first responder. While I haven't looked at that specific example, it probably allows the table to be editable.
I needed to override canBecomeFirstResponder in a custom UIView so I could use a custom InputView and InputAccessoryView.
Custom Views for Data Input
I had to do it this way because if I used a UITextField or UITextView, a hardware keyboard would subvert the more limited on-screen keyboard.

Moving view up to accommodate keyboard

I have a view with multiple text fields and I want to do the same effect that the Contacts application does when you click on a text field would otherwise be hidden by the keyboard when it comes up. When I dismiss the keyboard I plan on moving the view back down properly.
I suspect that I do this by changing the Frame value, but I need this to be animated so that it isn't jarring to the user.
Advice? Examples?
Wrapping your view in a UIScrollView is indeed the way to go. As well as on the textFieldDidEndEditing delegate, you could instead subscribe to the UIKeyboardDidHideNotification and UIKeyboardDidShowNotification and when you receive a notification that the keyboard did hide/show then scroll your view appropriately. I can post code examples for the keyboard notifications if you need it : )
Edit
Figured I'd post the code anyway - someone might find it helpful:
You need to declare listeners for the notifications:
NSObject hideObj = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.DidHideNotification, HandleKeyboardDidHide);
NSObject showObj = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.DidShowNotification, HandleKeyboardDidShow);
then your Action methods would look something like:
void HandleKeyboardDidShow(NSNotification notification)
{
scrollView.ScrollRectToVisible(textfield.Frame, true);
}
void HandleKeyboardDidHide(NSNotification notification)
{
// scroll back to normal
}
Edit 2
So if you'd like to remove the Observers when the view is destroyed, first you need to ensure you assign NSObjects when adding the observers then use the following code to remove them:
NSNotificationCenter.DefaultCenter.RemoveObserver(showObj);
NSNotificationCenter.DefaultCenter.RemoveObserver(hideObj);
Hope that helps.
I just did this on an application. I used a scrollview to wrap my entire view, and then used scrollToRectVisible on the textFieldDidEndEditing-delegate method. It worked perfectly!
The Apple documentation on about the keyboard management topic is pretty good and contains code (at the bottom) for most situations that that you can copy/paste right into your app.
Best of luck.