Search code examples
iosuitextfieldpdfview

Configuring keyboard settings within PDFView form fields


I'm working on an app which loads PDF files from a server and displays those PDF files within a PDFView. The files contain form fields in which the user is to type. That's works fine. The PDF files are to be used in an education setting, where the spelling should not be autocorrected and predictive text should not be available.

I have not found the means to disable autocorrect in a PDFView, along the lines of autocorrectionType = false in a UITextField.

I'm aware the user can manually disable autocorrection and predictive text in device settings. That's not a viable option in this case (likely user confusion and no means to verify). I'm ok if there's a way to disable autocorrect app-wide.

We're creating the PDF files in-house, so we're ok if there's something we can do while generating the files. Adobe Acrobat is a "check spelling" option on form fields, but the setting has no effect, at least within PDFView.

Thanks.


Solution

  • I found a solution. It's a hack, but I'll take what I can get.

    I found that when a user taps a PDF text field, PDFKit hides the PDF text field and overlays a UITextView at the same location. It makes that UITextView the first responder and brings up the keyboard. That UITextView remains until the user taps elsewhere, when it is removed and replaced with a PDF text field containing the contents of the (now dead) UITextView.

    The UITextView in question is buried deep inside PDFView, within private UIView subclasses.

    Below is the code I'm using. It starts with a view (the PDFView) and deep-dives looking for any UITextView it can find. When found, it resigns as first responder, changes parameters, and becomes the first responder again. The user will see the typeahead buttons appear briefly then disappear. I haven't found a way around this, as we don't gain access to the UITextView until it is already the first responder.

    The code here is called via a timer executing every 0.1 seconds. I'm sure there are more efficient ways to do this but this works, and barely registers on the CPU meter.

    This code also sets the pasteDelegate of the UITextView because in my case I want to override and prevent pasting of text into the UITextView. The code to do that is simple; in textPasteConfigurationSupporting just return [item setNoResult].

    As with all hacks like this, be sure to test with all versions of iOS your app supports - including future versions. Apple could easily change their PDFKit implementation causing this to break or misbehave. Or better, they could add a supported means to do this.

    -(void)lookForTextViewsInView:(UIView *)view
      for (UIView *subview in view.subviews) {
        if ([subview isKindOfClass:[UITextView class]]) {
            UITextView *textView = (UITextView *)subview;
            //NSLog(@"Found text field with contents: %@",textView.text);
            if (textView.autocapitalizationType == UITextAutocapitalizationTypeNone &&
                textView.autocorrectionType == UITextAutocorrectionTypeNo &&
                textView.spellCheckingType == UITextSpellCheckingTypeNo &&
                textView.pasteDelegate == self) {
                //NSLog(@"textView %@ is already adjusted", textView.text);
                return;
            }
            if (textView.isFirstResponder) {
                //NSLog(@"Adjusting and resetting first responder of %@",textView.text);
                [textView resignFirstResponder];
                textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
                textView.autocorrectionType = UITextAutocorrectionTypeNo;
                textView.spellCheckingType = UITextSpellCheckingTypeNo;
                textView.pasteDelegate = self;
                [textView becomeFirstResponder];
            } else {
                //I don't think this ever fires, but here for completion's sake
                //NSLog(@"Adjusting without resetting first responder of %@",textView.text);
                textView.autocapitalizationType = UITextAutocapitalizationTypeNone;
                textView.autocorrectionType = UITextAutocorrectionTypeNo;
                textView.spellCheckingType = UITextSpellCheckingTypeNo;
                textView.pasteDelegate = self;
            }
        } else {
            //NSLog(@"%@ is not a UITextView", [subview class]);
            [self lookForTextViewsInView:subview];
        }
      }
    }