My Share Extension doesn't require any user input aside from configuration in a table view so I am trying to hide the keyboard when the view is presented in Safari. I'm able to run my code in the simulator fine but when I test on my device, I'm the Share Extension doesn't launch and Safari hangs.
I've tried a few ways to prevent the keyboard from launching
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.textView.text = #"\n Place Holder Text";
self.textView.editable = NO;
}
As well, I tried it in loadView since that is where SLComposeServiceViewController
sets the textView and the textView delegate.
-(void)loadView{
[super viewWillAppear:animated];
self.textView.text = #"\n Place Holder Text";
self.textView.editable = NO;
}
And just for fun
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView{
return NO;
}
All of these work on the Simulator but not on my device.
What could be happening?
Is there some kind of Notification or Observer that I'm (or Safari is) missing
You just need to put your code in "viewDidAppear" function.
It works fine for me.
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.textView setText:#" Place Holder Text"];
[self.textView setEditable: NO];
}
Related
I've spent quite a bit of time searching online and talking to other developers about this issue to no avail. The exact issue is described in this SO post (Focus on the UISearchBar but the keyboard not appear), although it's many years old.
I recently switched from using the deprecated UISearchDisplayController and UISearchBar in IB, and switched over to UISearchController via the code for iOS8.
The problem I'm getting however, is that focus is assigned correctly (you can tell because the cancel button animates to the right of the search bar after the view loads), however the keyboard does not show up.
Here's the code that I have.
.h
#property (nonatomic, strong) UISearchController *searchController;
.m
- (void)viewDidLoad {
[super viewDidLoad];
...
[self initializeSearchController];
....
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.searchController setActive:YES];
[self.searchController.searchBar becomeFirstResponder];
}
- (void)initializeSearchController {
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.delegate = self;
self.searchController.searchBar.delegate = self;
[self.searchController.searchBar sizeToFit];
[self.tableView setTableHeaderView:self.searchController.searchBar];
self.definesPresentationContext = YES;
}
The things I've tried so far.
I've tried calling becomeFirstResponder on a 0.2 second delay, as suggested in another SO post.
I've set a breakpoint in viewDidAppear, and verified that both self.searchController and self.searchController.searchBar are both valid objects, neither nil.
I've tried conforming to the UISearchControllerDelegate and using the following snippet of code
here:
- (void)didPresentSearchController:(UISearchController *)searchController {
//no matter what code I put in here to becomeFirstResponder, it doesn't
//matter because this is never called, despite setting the
//self.searchController.delegate = self AND
//self.searchController.searchBar.delegate = self.
}
I've created a new view from scratch in storyboards, and segued to that one instead, to make sure I didn't have some old searchBar remnant in my view. This did not work either.
I've only tested this on a real device (iPhone 6), and it's not a simulator issue of not showing the keyboard.
I'm out of ideas, and I've seen every question and answer related to this one the web. Nothing is working.
To clarify again what's going on, the searchBar correctly becomes the first responder, the cancel button to the right of it animates onscreen proving this, but the keyboard does not appear and the cursor does not blink in the searchBar.
Your code looks ok. What you are describing isn't normal behaviour.
The first thing you can do is to create a new project with just the UISearchController functionality and see how it goes. You can edit your question with it so we'll have a better view.
There's a good example on how to implement UISearchController here: Sample-UISearchController
Adding:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.searchController.searchBar becomeFirstResponder];
}
to MasterViewController_TableResults.m gave the expected results and the keyboard popped up on launch on an iPad & iPhone with iOS 8.3.
You can go over that project and see what you did differently,
Edit:
Apparently if [self.searchController setActive:YES] is called before becomeFirstResponder the keyboard won't show. I wonder if that's a bug or not.
Had the same annoying issue.
You would think that by setting the SearchController as active would both present the the search controller and the keyboard. Unfortunately, it only does the first part.
My solution
in viewDidAppear make the Search Controller active:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
resultSearchController.active = true
}
once it is active, in didPresentSearchController make as first responder
func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.becomeFirstResponder()
}
Swift 3.0 (iOS 10) working solution:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
searchController.isActive = true
DispatchQueue.main.async { [unowned self] in
self.searchController.searchBar.becomeFirstResponder()
}
}
On iOS 9 I've found its sufficient to delay becomeFirstResponder() to the next run loop:
func focusSearchField() {
searchController?.active = true
// skipping to the next run loop is required, otherwise the keyboard does not appear
dispatch_async(dispatch_get_main_queue(), { [weak self] in
self?.searchController?.searchBar.becomeFirstResponder()
})
}
Working Solution:-
Don't use [self.searchController setActive:YES] before becomeFirstResponder.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
// [self.searchController setActive:YES];
[self.searchController.searchBar becomeFirstResponder];
});
});
}
In iOS 10, I had to run the code in delegate method on main thread. First I set the active to YES in viewDidAppear,
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self.searchController setActive:YES];
}
and then in the delegate method:
- (void)didPresentSearchController:(UISearchController *)searchController
{
dispatch_async(dispatch_get_main_queue(), ^{
[searchController.searchBar becomeFirstResponder];
});
}
The solution that will work is as follows :
1.Override ViewDidLayoutSubviews in the view controller in which you are showing UISearchController
2.Override ViewDidLayoutSubviews and inside it make search bar first responder.
Tested it on iOS > 9.0
Caution : Put a null check before making it First responder as follows
if((searchController != null)&&(searchController.SearchBar != null))
searchController.SearchBar.BecomeFirstResponder();
This is because ViewDidLayoutSubviews also gets called when cancel button is pressed.
This worked for me in Xamarin.
I had trouble with an UISearchBar not displaying the keyboard when doing
[searchBar becomeFirstResponder];
By searching on the net, i found this thread on the Apple developer website
that helped me to discover that the keyboard won't open if you don't have a keyWindow.
The application i work on do something like this :
Window A (KeyWindow)
do some things
open Window B (KeyWindow)
do some things
close Window B (resign KeyWindow)
I just had to do
[[[[UIApplication sharedApplication] windows] firstObject] makeKeyWindow];
after the resigning of window B and no more trouble with the keyboard.
This might also be related to Simulator Settings. Just disable Hardware -> Keyboard -> "Connect Hardware Keyboard" .
For further details: UISearchBar not showing keyboard when tapped
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.searchController setActive:YES];
}
//and then in the delegate method:
- (void)didPresentSearchController:(UISearchController *)searchController
{
dispatch_async(dispatch_get_main_queue(), ^{
[searchController.searchBar becomeFirstResponder];
});
}
//The above works for me in addition to this I had to add:
-(void)viewWillDisappear:(BOOL)animated {
[searchController setActive:NO];
}
I'm implementing a share extension for my app, so far everything is going good except I can't seem to dismiss the keyboard that automatically opens using the default layout/storyboard.
I'm keeping the default design/layout (SLComposeServiceViewController) which includes the preview image and UITextview, the UITextview automatically gets in focus which opens the keyboard.
Normally this is fine, but if you're not logged in my app I display an UIAlertController saying you need to login to share. The problem is the keyboard opens at the same time as the alert.
I've tried [self.view endEditing:YES]; and [self.textView resignFirstResponder]; in both viewDidLoad, viewDidAppear and viewWillAppear with no luck.
Found the answer! I didn't read the docs very carefully...
I had to do [self.textView resignFirstResponder]; in -(void)presentationAnimationDidFinish
my way is to use UITextViewDelegate
- (void)viewDidLoad {
[super viewDidLoad];
self.textView.delegate = self;
self.canShare = NO;
[self.view setAlpha:0.0];
}
change canShare to YES in your check login logic
- (void)checkLoggedIn {
if ([[ShareAccountManager checkLoggedIn]) {
self.canShare = YES;
[self.view setAlpha:1.0];
}
}
and implement method textViewShouldBeginEditing
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
if (self.canShare) {
return YES;
}
return NO;
}
I am using the following custom keyboard:
https://github.com/kulpreetchilana/Custom-iOS-Keyboards
How do you make it so that they keyboard is displayed at the beginning without having to touch the text view?
Depending on the version of iOS you're using (not sure if it works on 8), you can do:
- (void)viewDidLoad;
{
[super viewDidLoad];
[self.textField becomeFirstResponder];
}
Or
- (void)viewDidLayoutSubviews;
{
[super viewDidLayoutSubviews];
[self.textField becomeFirstResponder];
}
In your ViewController.
Tapping a text view will call becomeFirstResponder on it.
So you should be able to make the keyboard appear with...
[textView becomeFirstResponder];
I've never used that framework though so not 100% sure.
How is that possible that my editable UITextView (placed inside a straightforward UIViewController inside a UISplitView that acts as delegate for the UITextView) is not showing text from the beginning but after something like 6-7 lines?
I didn't set any particular autolayout or something similar, trying to delete text doesn't help (so no hidden chars or something).
I'm using iOS 7 on iPad, in storyboard looks good...
The problem is the same on iOS simulator and real devices. I'm getting mad :P
Here's some code. This is the ViewController viewDidLoad()
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.itemTextField.delegate = self;
self.itemTextField.text = NSLocalizedString(#"NEWITEMPLACEHOLDER", nil);
self.itemTextField.textColor = [UIColor lightGrayColor]; //optional
}
And here are the overridden functions for the UITextView I'm using some code I've found on StackOverflow to simulate a placeholder for the view (the same stuff on iPhone version of the storyboard works fine)...
// UITextView placeholder
- (void)textViewDidBeginEditing:(UITextView *)textView
{
if ([textView.text isEqualToString:NSLocalizedString(#"NEWITEMPLACEHOLDER", nil)]) {
textView.text = #"";
textView.textColor = [UIColor blackColor]; //optional
}
[textView becomeFirstResponder];
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
if ([textView.text isEqualToString:#""]) {
textView.text = NSLocalizedString(#"NEWITEMPLACEHOLDER", nil);
textView.textColor = [UIColor lightGrayColor]; //optional
}
[textView resignFirstResponder];
}
-(void)textViewDidChange:(UITextView *)textView
{
int len = textView.text.length;
charCount.text = [NSString stringWithFormat:#"%#: %i", NSLocalizedString(#"CHARCOUNT", nil),len];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return YES;
}
Try to call -sizeToFit after passing the text. This answer could be useful to Vertically align text within a UILabel.
[UPDATE]
I update this answer o make it more readable.
The issue is that from iOS7, container view controllers such as UINavigationController or UITabbarController can change the content insets of scroll views (or views that inherit from it), to avoid content overlapping. This happens only if the scrollview is the main view or the first subviews. To avoid that you should disable this behavior by setting automaticallyAdjustsScrollViewInsets to NO, or overriding this method to return NO.
I got through the same kind of issue.
Solved it by disabling the automatic scrollView insets adjustement :
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")){
self.automaticallyAdjustsScrollViewInsets = NO; // Avoid the top UITextView space, iOS7 (~bug?)
}
This is a fairly common problem, so I would create a simple UITextView subclass, so that you can re-use it and use it in IB.
I would used the contentInset instead, making sure to gracefully handle the case where the contentSize is larger than the bounds of the textView
#interface BSVerticallyCenteredTextView : UITextView
#end
#implementation BSVerticallyCenteredTextView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self addObserver:self forKeyPath:#"contentSize" options: (NSKeyValueObservingOptionNew) context:NULL];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
[self addObserver:self forKeyPath:#"contentSize" options: (NSKeyValueObservingOptionNew) context:NULL];
}
return self;
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"contentSize"])
{
UITextView *tv = object;
CGFloat deadSpace = ([tv bounds].size.height - [tv contentSize].height);
CGFloat inset = MAX(0, deadSpace/2.0);
tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right);
}
}
- (void)dealloc
{
[self removeObserver:self forKeyPath:#"contentSize"];
}
#end
use -observerForKeyPath with contentSize KeyPath
Look some code at My Blog (don't focus on Thai Language)
http://www.macbaszii.com/2012/10/ios-dev-uitextview-vertical-alignment.html
Inspired by Kiattisak, I've implemented vertical alignment as a category over UITextView so that you can control the vertical alignment of legacy UITextView.
You can find it as a gist here.
I had the same issue with iOS 8.1, and none of these suggestions worked.
What did work was to go into the Storyboard, and drag my UITableView or UITextView so that it was no longer the first subview of my screen's UIView.
http://www.codeproject.com/Tips/852308/Bug-in-XCode-Vertical-Gap-Above-UITableView
It seems to be linked to having a UIView embedded in a UINavigationController.
Bug ? Bug ? Did I say "bug" ...?
;-)
Swift version of Tanguy.G's answer:
if(UIDevice.currentDevice().systemVersion >= "7.0") {
self.automaticallyAdjustsScrollViewInsets = false; // Avoid the top UITextView space, iOS7 (~bug?)
}
Check top content inset of textView in -viewDidLoad:
NSLog(#"NSStringFromUIEdgeInsets(self.itemTextField.contentInset) = %#", NSStringFromUIEdgeInsets(self.itemTextField.contentInset));
Reset it in storyboard if it is not zero
In my app i have UITextField on view of VC1(UIViewController). When i change text in textfield i call pushing of another controller VC2 with UISearchBar on its view. After pushing im assigning UISearchBar text to the textfield text from VC1.
On xib my textfield already have some text "Test string".
When I'm append VC1 textfield with any char - VC2 pushing and text on searchbar is normal.
But when I'm press backspace key on iPhone keyboard - VC2 pushed and text on searchfield start deleting char by char, while whole string not been empted. It happend because delegate method calls recursively.
How to fix that behaviour of UISearchBar? I mush to have searchbar active with keyboard opened when VC2 appears! It's main condition. Sure, if i'll remove [self.searchBar becomeFirstResponder] all will works fine.
Some code here:
#implementation ViewController1
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString * resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
ViewController2 * vc2 = [ViewController2 new];
[self.navigationController pushViewController:vc2 animated:YES];
[vc2 loadText: resultString];
return NO;
}
#end
#implementation ViewController2
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.searchBar becomeFirstResponder];
}
- (void) loadText: (NSString *) text
{
self.searchBar.text = text;
}
#end
Sample source code of the problem: http://yadi.sk/d/NJmTLot73_vrE
I've gone through the code and for some reason the delete/backspace key is getting called repeatedly by the UIKeyboard's Accessibility function. I haven't been able to find a reason yet but one workaround is to put the [self.searchBar becomeFirstResponder]; line into viewDidAppear instead of viewWillAppear - is that an acceptable workaround? The keyboard animation is slightly different but I'm not sure how sensitive your needs are to that.
I've been experiencing strange UISearchBar animations on iOS 7. Solved the problem by putting my becomeFirstResponder call in viewDidAppear with a delay of 0.1.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.searchBar performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.1];
}
You have a recursive call in your code.
self.searchBar.text = text;
calls to
textField:shouldChangeCharactersInRange:
which in turn calls to
loadText:
What you can do is remove the delegate from the searchBar uitextfield, set the text and then return the delegate. Something like this:
- (void) loadText: (NSString *) text
{
self.searchBar.delegate = nil;
self.searchBar.text = text;
self.searchBar.delegate = vc1;
}