We do have an input bar at the bottom of the screen and want to keep the keyboard up when switching the UIViewController. The keyboard get dismissed automatically and i couldn't find anything to prevent from this.
How do we prevent the keyboard from being dismissed when we change the UIViewController with a UIStoryboardSegue?
There is a property called disablesAutomaticKeyboardDismissal that you need to set to false to prevent this from happening.
There is a way to keep a keyboard on:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(coverKey) name:UIKeyboardDidShowNotification object:nil];
[super viewDidLoad];
}
- (void)coverKey {
CGRect r = [[UIScreen mainScreen] bounds];
UIWindow *myWindow = [[UIWindow alloc] initWithFrame:CGRectMake(r.size.width - 50 , r.size.height - 50, 50, 50)];
[myWindow setBackgroundColor:[UIColor clearColor]];
[super.view addSubview:myWindow];
[myWindow makeKeyAndVisible];
}
Related
I would like to add a textfield and send button that sticks to the bottom of uitableview similar to a chat app. I have come across comments on embedding a UITableView as a container view within a UIViewController.
However, they seem to lack an example on how to achieve this. More specifically details including where to add a textfield/button and move textfield up when keyboard appears, etc. Thanks!
follow the steps using the storyboard
1) drag a uiviewcontroller from the object library.
2) drag and drop the textfield and button and place it at the position you want
3) drag and drop a container view.
4) delete the default uiviewcontroller comes with the container view
5) drag a uitableviewcontroller and make a segue and the segue should be embedsegue.
and for keyboard handling you can go with IQKeyboardManager library https://github.com/hackiftekhar/IQKeyboardManager
A very simple chat model code, you can take a look:
#import "ViewController.h"
#interface ViewController ()
#property UIView* containerView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_containerView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
UITableView* tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-30)];
UITextField* tfInput = [[UITextField alloc] initWithFrame:CGRectMake(0, tableView.frame.size.height, [UIScreen mainScreen].bounds.size.width-50, 30)];
tfInput.backgroundColor = [UIColor grayColor];
UIButton* btnSend = [[UIButton alloc] initWithFrame:CGRectMake(tfInput.frame.size.width, tfInput.frame.origin.y, 50, 30)];
[btnSend setTitle:#"Send" forState:UIControlStateNormal];
[btnSend setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnSend addTarget:self action:#selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];
[_containerView addSubview:tableView];
[_containerView addSubview:tfInput];
[_containerView addSubview:btnSend];
[self.view addSubview:_containerView];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
float keyboardHeight = [aValue CGRectValue].size.height;
//Resize the container
_containerView.frame = CGRectMake(0, - keyboardHeight, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
}
-(void)btnClicked{
[self.view endEditing:YES];
}
- (void)keyboardWillHide:(NSNotification *)notification {
_containerView.frame = [UIScreen mainScreen].bounds;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is a screenshot for using storyboard:
For an iPhone app with users entering their data into text boxes,
I need the page to scroll both when the text boxes are selected for user to input and when keyboard has not been opened for user to review what they entered.
When using the Interface Builder and overlaying the scroll view, I can't get it to stay or save so that the page is actually scrollable.
I would also prefer to do this programmatically. Other solutions like this have not worked when inserted into the .m file.
#property (weak, nonatomic) IBOutlet UIScrollView *topScrollView;
#synthesize topScrollView;
[topScrollView setFrame:CGRectMake(320, 0, 320, 65)];
[topScrollView setContentSize:CGSizeMake(500, 100)];
[topScrollView setBackgroundColor:[UIColor greenColor]];
[topScrollView setScrollEnabled:YES];
[topScrollView setShowsHorizontalScrollIndicator:YES];
[topScrollView setShowsVerticalScrollIndicator:NO];
[[self view] addSubview:topScrollView];
You can place a UIView with all your textfields on top of the main view and set NSNotifications for the keyboard and move the view around accordingly.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidShowWithNotification:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHideWithNotification:) name:UIKeyboardWillHideNotification object:nil];
#pragma mark NSNotifications
- (void)keyboardDidShowWithNotification:(NSNotification *)aNotification
{
const int movementDistance = ([UIScreen mainScreen].bounds.size.height == 568 ? 155 : 180);
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState
animations:^{
CGPoint adjust = CGPointMake(0, -movementDistance);
CGPoint newCenter = CGPointMake(self.loginContainer.center.x+adjust.x, self.loginContainer.center.y+adjust.y);
[self.loginContainer setCenter:newCenter];
}
completion:nil];
}
- (void)keyboardDidHideWithNotification:(NSNotification *)aNotification
{
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.loginContainer.frame = CGRectMake(0, 0, self.loginContainer.frame.size.width, self.loginContainer.frame.size.height);
}
completion:nil];
}
I would like to have a keyboard with a non-transparent keyboard - I couldn't get this with any of the supported UIKeyboardTypes. Is there another way around this?
I suppose I could just overlay a background view under the keyboard with the color I want - would there be a good way to animate that background view in sync with the keyboard show animation?
The keyboard in iOS7 is translucent when app is compiled in Xcode 5 with a Base SDK of iOS 7.
If you build the app on Xcode 4.6.x instead, you'll have the non-translucent keyboard as before.
(i know this is a shitty fix but nonetheless, i thought i'd suggest it)
anyways, you could alternatively try making use of the default keyboard notifications:
UIKeyboardWillShowNotification
UIKeyboardWillHideNotification
should go something like:
-(void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
-(void)keyboardWillShow:(NSNotification *)note
{
/*
Would have used:
CGRect rectStart = [note.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect rectEnd = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
Reason for not using:
The above two keys are not being used although, ideally, they should have been
since they seem to be buggy when app is in landscape mode
Resolution:
Using the deprecated UIKeyboardBoundsUserInfoKey since it works more efficiently
*/
CGRect rectStart_PROPER = [note.userInfo[UIKeyboardBoundsUserInfoKey] CGRectValue];
rectStart_PROPER.origin.y = self.view.frame.size.height;
UIView *vwUnderlay = [self.view viewWithTag:8080];
if (vwUnderlay) {
[vwUnderlay removeFromSuperview];
}
vwUnderlay = [[UIView alloc] init];
[vwUnderlay setFrame:rectStart_PROPER];
[vwUnderlay setBackgroundColor:[UIColor orangeColor]];
[vwUnderlay setTag:8080];
[self.view addSubview:vwUnderlay];
[UIView animateWithDuration:[note.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
delay:0
options:[note.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16
animations:^{
[vwUnderlay setFrame:CGRectOffset(vwUnderlay.frame, 0, -vwUnderlay.frame.size.height)];
}
completion:nil];
}
-(void)keyboardWillHide:(NSNotification *)note
{
UIView *vwUnderlay = [self.view viewWithTag:8080];
[UIView animateWithDuration:[note.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]
delay:0
options:[note.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16
animations:^{
[vwUnderlay setFrame:CGRectOffset(vwUnderlay.frame, 0, vwUnderlay.frame.size.height)];
}
completion:^(BOOL finished){
[vwUnderlay removeFromSuperview];
}];
}
Apple does not allow anyone to modify the default keyboard. If you are going to be using iOS 7 then you will have to deal with the translucent keyboard.
The only other way I can think of is designing your own keyboard, but that's a tedious process to go through.
I was looking into the same thing today, and I found a simple workaround (although, not yet sure how reliable it is).
In order to work, I've set up an inputAccessoryView for my keyboard controls (UITextView and UITextField). In the UIView class that I've set as the inputAccessoryView I added the followings:
-(void)layoutSubviews{
[super layoutSubviews];
frame = _lKeyboardBackground.frame;
frame.origin.y = [self convertPoint:self.frame.origin toView:self.superview].y+self.frame.size.height;
frame.size.width = self.bounds.size.width;
frame.origin.x = 0;
frame.size.height = 500;
_lKeyboardBackground.frame = frame;
[self refreshKeyboardBackground];
}
-(void)didMoveToSuperview{
[super didMoveToSuperview];
if (self.superview) {
[self.superview.layer insertSublayer:_lKeyboardBackground atIndex:lMagicLayerIndex];
}
else {
[_lKeyboardBackground removeFromSuperlayer];
}
}
-(void)setFrame:(CGRect)frame{
[super setFrame:frame];
[self refreshKeyboardBackground]; // setFrame: is called when keyboard changes (e.g: to a custom input view)
}
-(void)refreshKeyboardBackground{
if (_lKeyboardBackground.superlayer) {
CALayer *parent = _lKeyboardBackground.superlayer;
[_lKeyboardBackground removeFromSuperlayer];
[parent insertSublayer:_lKeyboardBackground atIndex:lMagicLayerIndex];
}
}
_lKeyboardBackground is a CALayer that I've setup in the init methods:
_lKeyboardBackground = [CALayer layer];
_lKeyboardBackground.backgroundColor = [[UIColor redColor] CGColor]; //or some less annoying color
This should theoretically pass Apple's approval, but I never tested. There's also plenty of changes this will not work in future versions, or in some other situations (e.g when there's a split keyboard on the iPad)
lMagicLayerIndex that I use is 1, which gives the absolute color.
Note that the blur can still be noticed on key-strokes.
Use keyboard notification to show/hide a custom black view behind the keyboard (or white if you use the white keyboard) and voila, transparent no more.
I have a simple app that is targeting iPad and iOS 5+ only. The app is landscape-only. Now, I want to take advantage of AirPlay mirroring on the iPad 2.
I have followed all of Apple's examples/documentation I can find and can't get past this drawing problem. The secondary display doesn't draw in the correct orientation.
Below is the output I am seeing from a small test app. The blue box is just a simple UIView that should be taking up the entire screen, but is not. It seems to be drawing correctly in landscape, but the view is rotated 90 degrees. Notice how the blue extends past the margin on the bottom of the TV:
I think I need to somehow force the ViewController of the external window to correctly draw in landscape, but I don't know the proper way to do this. Any ideas?
Below are the relevant pieces code:
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(screenDidConnect:)
name:UIScreenDidConnectNotification
object:nil];
[self initScreens];
return YES;
}
- (void)screenDidConnect:(NSNotification *)note
{
[self initScreens];
}
- (void)initScreens
{
if ([[UIScreen screens] count] > 1)
{
UIScreen *screen = [[UIScreen screens] lastObject];
if (!self.secondaryWindow)
{
self.secondaryWindow = [[UIWindow alloc] initWithFrame:screen.bounds];
self.secondaryWindow.screen = screen;
self.secondaryWindow.hidden = NO;
}
if (!self.secondaryViewController)
{
self.secondaryViewController = [[CCKSecondaryViewController alloc] init];
}
self.secondaryWindow.rootViewController = self.secondaryViewController;
}
}
CCKSecondaryViewController.m: This is the rootViewController of the external window
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
view.backgroundColor = [UIColor blueColor];
self.view = view;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = #"Secondary Screen";
[label sizeToFit];
[self.view addSubview:label];
label.center = self.view.center;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
You can find the sample app here:
http://dl.dropbox.com/u/360556/AirplayTest.zip
It's displaying in portrait on the connected screen. Having your shouldAutorotateToInterfaceOrientation method always return NO should sort it out for you.
I have a toolbar which I need to use when editing text, and when not.
In previous apps, I've moved the toolbar manually (listening for notifications, etc.)
But I want to use inputAccessoryView... so in my viewDidLoad, I do
for (/*myTextFields*/) {
textField.inputAccessoryView = keyboardToolbar;
}
[self.view addSubView:keyboardToolbar];
Which works fine, the toolbar appears, I click on a text field, toolbar slides up - all good.
But when I then hide the keyboard, inputAccessoryView drags my toolbar off the screen. Is there any way to tell the inputAcessoryView where it's fixed location is? - Or do I have to go back to my old way of listening for notifications etc...?
I solved this by listening for Notifications and moving the toolbar up... oh well.
Something like this does the job:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
/* Listen for keyboard */
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
[keyboardToolbar setItems:itemSetFull animated:YES];
/* Move the toolbar to above the keyboard */
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.view.frame.size.height - 210.0;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
[keyboardToolbar setItems:itemSetSmall animated:YES];
/* Move the toolbar back to bottom of the screen */
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.view.frame.size.height - frame.size.height;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}
I guess input accessory view is literally just meant for something stuck on top of the keyboard :)
I've figured it out recently, and it seems few people have. So, I would like to direct you to this answer: https://stackoverflow.com/a/24855095/299711, which I will just copy below:
Assign your UIToolbar to a property in your view controller:
#property (strong, nonatomic) UIToolbar *inputAccessoryToolbar;
In your top view controller, add these methods:
- (BOOL)canBecomeFirstResponder{
return YES;
}
- (UIView *)inputAccessoryView{
return self.inputAccessoryToolbar;
}
And then (optionally, as it usually shouldn't be necessary), whenever the keyboard gets hidden, just call:
[self becomeFirstResponder];
That way, your inputAccessoryToolbar will be both your view controller's and your text view's input accessory view.