How to overlay on top of the Keyboard in xcode - iphone

How do you overlay something, ie a UIImageView over the keyboard which pops up when editing a UITextFIeld?

You can catch keyboard window using following code, if you put it into textFieldDidBeginEditing method:
UIWindow* keyboard = [[[UIApplication sharedApplication] windows] objectAtIndex:1];

Related

How to change UIDocumentInteractionController preview screen?

We have a requirement to change UIDocumentInteractionController preview screen? Is it possible to change the rect of UIDocumentInteractionController? I want to open document preview in my custom view?
in creating an AIR Native Extension, I needed to create a view window for my custom view controller.
make sure you are doing:
#import "MyCustomViewController.h"
in my function:
MyCustomViewController *myViewController;
id delegate = [[UIApplication sharedApplication] delegate];
UIWindow *win = [delegate window];
myViewController = [[MyCustomViewController alloc]init];
[win addSubview:myViewController.view];
[myViewController previewDocument: (parameters to method)];
return (_bridge FREObject)(myViewController);
where you implement this may be different depending on your structure. Since I am using it as an ANE, I put it right into the Context function call.
hope it gives you a starting point if you haven't gotten it yet.

Why is the keyboard not showing when view loads?

I have this code in my viewdidload:
[_txtName setDelegate:self];
[_txtName becomeFirstResponder];
_txtName.enabled = YES;
_txtName.text = #"";
But when my view loads, the keyboard does not show, any idea why?
_txtName is the UITextField
As pointed out in a comment by #lukya you should place the call to becomeFirstResponder in either viewWillAppear: or viewDidAppear:. If you place the call in viewWillAppear: the keyboard will be shown on screen when the view is shown. If you would like the keyboard to animate in from the bottom when the view appears you should put the call in viewDidAppear:.

how to get my UIWindow using UIApplication?

I have only one window and I tried
UIWindow* mWindow = [[UIApplication sharedApplication] keyWindow];
but this returned nil.
I also tried:
UIWindow* mWindow = (UIWindow*)[[UIApplication sharedApplication].windows objectAtIndex:0];
But this raised an exception and the app closed, when I tried to print out
[[UIApplication sharedApplication].windows count]
It printed 0
Note: I am putting this in my only view controller's viewDidLoad method and this is completely a new iPad View Based Application so I changed nothing, just trying to get the window
Please help me to get this object
If your main window is an outlet of your AppDelegate (which should be the case), you may simply use
MyAppDelegate* myDelegate = (((MyAppDelegate*) [UIApplication sharedApplication].delegate));
[myDelegate.window ...]
Easiest way is to get the window from the app delegate instead:
UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
// Do something with the window now
Your application's key window isn't set until [window makeKeyAndVisible] gets called in your app delegate. Your UIViewController is probably being loaded from a NIB before this call. This explains why keyWindow is returning nil.
Luckily, your view controller doesn't need to go through UIApplication to get the window. You can just do:
UIWindow *mWindow = self.view.window;
[[[UIApplication sharedApplication] windows] objectAtIndex:0]; // You can also check the count of this to make sure, because if there are no windows it will crash.
With iOS 13+ you should use:
if let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = currentScene.keyWindow {
// now window contains the active window
}
You can achieve this in multiple ways. I like to use one of the following.
Use this when you need to access it just once.
if let window = UIApplication.shared.windows.first as UIWindow? {
// Action
}
If you need to access the UIWindow multiple times, I would suggest extending a class. I like to extend the UIViewController.
extension UIViewController {
/// Returns the UIWindow if available.
public var window: UIWindow? {
UIApplication.shared.windows.first as UIWindow?
}
}

Orientation in a UIView added to a UIWindow

I have a UIView which is supposed to cover the whole device (UIWindow) to support an image zoom in/out effect I'm doing using core animation where a user taps a button on a UITableViewCell and I zoom the associated image.
The zooming is performing flawlessly, what I haven't been able to figure out is why the subview is still in portrait mode even though the device is in landscape. An illustration below:
I do have a navigation controller but this view has been added to the UIWindow directly.
You can read about some of the possible causes here:
Technical Q&A QA1688 - Why won't my UIViewController rotate with the device?
In your situation its probably the fact that you are adding the view as another subview to the window. Only the first subview gets the rotation events. What you can do is add it as a subview of the first window subview.
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window)
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:myView];
The problem
Beginning with iOS 6, only the topmost view controller (alongside the
UIApplication object) participates in deciding whether to rotate in
response to a change of the device's orientation.
https://developer.apple.com/library/content/qa/qa1688/_index.html
The solution
I have open sourced a pod named AGWindowView.
It will automatically deal with any rotation and framechanges so you won't have to worry about that.
The code
It supports any combination of SDK's and iOS system versions. The relevant code can be found here:
https://github.com/hfossli/AGWindowView/blob/master/Source/AGWindowView.m
I created a category on UIApplication that has a helper property and method for getting the first subview of the keyWindow. This is the view you want to overlay anyway. Now when you add a view that is managed by a UIViewController to that view, the shouldRotateToInterfaceOrientation: method is called.
UIApplication+WindowOverlay.h
#import <UIKit/UIKit.h>
#interface UIApplication(WindowOverlay)
#property (nonatomic, readonly) UIView *baseWindowView;
-(void)addWindowOverlay:(UIView *)view;
#end
UIApplication+WindowOverlay.m
#import "UIApplication+WindowOverlay.h"
#implementation UIApplication(WindowOverlay)
-(UIView *)baseWindowView{
if (self.keyWindow.subviews.count > 0){
return [self.keyWindow.subviews objectAtIndex:0];
}
return nil;
}
-(void)addWindowOverlay:(UIView *)view{
[self.baseWindowView addSubview:view];
}
#end
and here is how you would use it.
//at the top of the file...or in {yourproject}.pch
#import "UIApplication+WindowOverlay.h
//in a method:
UIView *view = [UIView new];
UIView *window = [UIApplication sharedApplication].baseWindowView;
view.frame = window.bounds;
[window addSubview:view];
//or
[[UIApplication sharedApplication] addWindowOverlay:view];
This is because as you mention your view has been added directly to the UIWindow, therefore when the method to rotate is called for the navigation controller nothing happens to the uiview. The UIView would rotate if it was a subview of the view controller view. If for some reason this cannot be done. Then you could override this method:
// This method is called every time the device changes orientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
}
And every time your orientation changes also change your view orientation.
I had a similar problem with views being added directly to a window. Maybe this will help: Automatically Sizing UIView after Adding to Window
Another solution how I solved this problem.
Define the current Orientation:
#interface AJImageCollectionViewController (){
UIInterfaceOrientation _currentOrientation;
}
#end
Then check the orientation in the viewWillLayoutSubviews:
- (void)viewWillLayoutSubviews {
[self checkIfOrientationChanged];
}
- (void)checkIfOrientationChanged {
UIInterfaceOrientation newOrientation = [[UIApplication sharedApplication] statusBarOrientation];
BOOL newOrientationIsPortrait = UIInterfaceOrientationIsPortrait(newOrientation);
BOOL oldOrientationIsPortrait = UIInterfaceOrientationIsPortrait(_currentOrientation);
// Check if the orientation is the same as the current
if(newOrientationIsPortrait != oldOrientationIsPortrait){
_currentOrientation = newOrientation;
// Do some stuff with the new orientation
}
}

iphone MFMailComposeViewController

Is there a way to dismiss the keyboard from MFMailComposeViewController ? If the user rotates the device, I am loading a separate controller without "send" or "cancel" being pressed, and the keyboard is remaining on screen. Is there an way to dismiss the keyboard without "done" or "send" being pressed?
You can find the first responder and ask it to resign active which should dismiss the keyboard.
UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView* firstResponder = [keyWindow performSelector:#selector(firstResponder)];
[firstResponder resignFirstResponder];