I have uiscrollview, 2 textviewfields and I read all the posts about keyboard hiding textview and tried many methods, but still it hides it.
My code is like this:
ViewController.h
#property(nonatomic,retain) IBOutlet UITextView *campaignTitle;
#property (weak, nonatomic) IBOutlet UITextView *campaignDescription;
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property UITextView *activeTextView;
ViewController.m
#synthesize campaignTitle;
#synthesize campaignDescription;
#synthesize scrollView;
#synthesize activeTextView;
#define SCROLLVIEW_CONTENT_HEIGHT 460
#define SCROLLVIEW_CONTENT_WIDTH 320
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
scrollView.contentSize=CGSizeMake(0, self.view.frame.origin.y+self.view.frame.size.height+50);
[super viewDidLoad];
}
- (BOOL) textViewShouldBeginEditing:(UITextView *)textView
{
textView.text = #"";
self.activeTextView = textView;
return YES;
}
- (BOOL) textViewShouldEndEditing:(UITextView *)textView
{
self.activeTextView = nil;
return YES;
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if([text isEqualToString:#"\n"])
[textView resignFirstResponder];
return YES;
}
- (void)keyboardWasShown:(NSNotification *)notification
{
// Step 1: Get the size of the keyboard.
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// Step 2: Adjust the bottom content inset of your scroll view by the keyboard height.
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0);
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
// Step 3: Scroll the target text field into view.
CGRect aRect = self.view.frame;
aRect.size.height -= keyboardSize.height;
if (!CGRectContainsPoint(aRect, activeTextView.frame.origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, activeTextView.frame.origin.y - (keyboardSize.height-15));
[scrollView setContentOffset:scrollPoint animated:YES];
}
}
- (void) keyboardWillHide:(NSNotification *)notification {
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scrollView.contentInset = contentInsets;
scrollView.scrollIndicatorInsets = contentInsets;
}
- (IBAction)dismissKeyboard:(id)sender
{
[self.activeTextView resignFirstResponder];
}
There is delegation from the scroll view and campaignTitle, campaignDescription.
What is wrong? why the keyboard still hiding the bottom uitextview? The extra code that you may see is to support Return button in UITextView
Or use TPKeyboardAvoiding.
It is working great, and is very easy to setup:
Add a UIScrollView into your view controller's xib
Set the scroll view's class to TPKeyboardAvoidingScrollView (still
in the xib, via the identity inspector)
Place all your controls within that scrollview
It also automatically hooks up "Next" buttons on the keyboard to switch through the text fields.
Make sure your UITextFields are actually inside of your UIScrollView inside your storyboard and not accidentally placed on the UIView below it.
setContentOffset should do SOMETHING, even if it is not the intended effect. Since it seems to be doing nothing, I'd suspect that either your UITextFields are not subviews of it or your UIScrollView is not wired up in interface builder.
Related
I have a table view where i m adding a cell for the content of the table view and i need to add swipeable gesture with 3 buttons in that that table cell.
u haven't provide enough info about how you are implementing the tableview cell but i assume that u are using the xib file and also i assume that u want to display the 3 button when table view cell is swiped ..
first of all u should subclass the table view cell in my example i named the cell class as CustomTableCell
in this cell's xib file i am adding the a view and 3 buttons, it is something look like below image
in the above image swipeView should be on top of content view and it holds your swipe gestures
for example in CustomTableCell.h file
#import <UIKit/UIKit.h>
#interface CustomTableCell : UITableViewCell
+ (id)createMenuCell;
#property (weak, nonatomic) IBOutlet UIView *swipeView;
#property (weak, nonatomic) IBOutlet UIButton *button3;
#property (weak, nonatomic) IBOutlet UIButton *button2;
#property (weak, nonatomic) IBOutlet UIButton *button1;
#property (assign, nonatomic) BOOL showButton;
- (IBAction)buttonOneAction:(id)sender;
- (IBAction)buttonTwoAction:(id)sender;
- (IBAction)buttonThreeAction:(id)sender;
#end
and in CustomTableCell.m file
#import "CustomTableCell.h"
#implementation CustomTableCell
#define MAX_LEFT 160 //set the how much view has to be move
#define ANIMATION_DUR 0.3
+ (id)createMenuCell
{
NSArray *xibElements = [[NSBundle mainBundle] loadNibNamed:#"CustomTableCell" owner:nil options:nil];
for(id item in xibElements)
{
if([item isKindOfClass:[CustomTableCell class]])
{
return (CustomTableCell *)item;
}
}
return nil;
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
[self setUpGestures];
}
return self;
}
- (void)awakeFromNib {
// Initialization code
_showButton = NO; //simple avoid unwanted swipes when showing the buttons
[self setUpGestures];
}
- (void)setUpGestures{
UISwipeGestureRecognizer *swipeLeftGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeLeftGestureAction)]; //to open
swipeLeftGesture.direction = UISwipeGestureRecognizerDirectionLeft; //set the direction to swipe
[self.swipeView addGestureRecognizer:swipeLeftGesture];
UISwipeGestureRecognizer *swipeRightGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRightGestureAction)]; //this is for closing
[self.swipeView addGestureRecognizer:swipeRightGesture];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
//button actions
- (IBAction)buttonOneAction:(id)sender {
NSLog(#"button one action");
}
- (IBAction)buttonTwoAction:(id)sender {
NSLog(#"button two action");
}
- (IBAction)buttonThreeAction:(id)sender {
NSLog(#"button three action");
}
//hear u are showing the buttons with left swipe
- (void)swipeLeftGestureAction
{
if(!_showButton)
{
CGRect destRect = self.swipeView.frame;
destRect.origin.x = -MAX_LEFT;
[UIView animateWithDuration:ANIMATION_DUR animations:^{
self.swipeView.frame = destRect;
} completion:^(BOOL finished) {
_showButton = YES;
}];
}
}
//hear u are hiding the buttons if it is shown
- (void)swipeRightGestureAction
{
if(_showButton)
{
CGRect destRect = self.swipeView.frame;
destRect.origin.x = 0;
[UIView animateWithDuration:ANIMATION_DUR animations:^{
self.swipeView.frame = destRect;
} completion:^(BOOL finished) {
_showButton = NO;
}];
}
}
Note: above is just i assumed so final result will be like below
I have a toolbar and made this code to learn how to put it above the keyboard when I open it however after doing this or the keyboard appears.
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITextView *textField;
#property (weak, nonatomic) IBOutlet UIToolbar *toolbar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textField.delegate = self;
self.toolbar.delegate = self;
self.textField.inputAccessoryView = self.toolbar;
self.textField.inputView = self.toolbar;
[self.toolbar removeFromSuperview];
[self.textField becomeFirstResponder];
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
self.textField.inputAccessoryView = self.toolbar;
}
Your line [self.toolbar removeFromSuperview]; is causing the toolbar to become nil, so it is not appearing.
And as #jammycoder said you only need to set inputAccessoryView of the text field. So do as he suggested and remove the line self.textField.inputView = self.toolbar;
Edit
I have setup a simple project and put a UIToolbar and a UITextView on the view controller, in the storyboard. Those two views are connected (IBOutlets) to the ViewController as you probably did,.
If I use your code it indeed does not show the keyboard, why? Because you are assigning the inputView of the UITextView.
So let's debug your code. First of all add bunch of NSLog statements like this.
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField.delegate = self;
NSLog(#"1 %#", NSStringFromCGRect(self.toolbar.frame));
self.textField.inputAccessoryView = self.toolbar;
NSLog(#"2 %#", NSStringFromCGRect(self.toolbar.frame));
self.textField.inputView = self.toolbar;
NSLog(#"3 %#", NSStringFromCGRect(self.toolbar.frame));
[self.toolbar removeFromSuperview];
NSLog(#"4 %#", NSStringFromCGRect(self.toolbar.frame));
[self.textField becomeFirstResponder];
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
NSLog(#"5 %#", NSStringFromCGRect(self.toolbar.frame));
self.textField.inputAccessoryView = self.toolbar;
NSLog(#"6 %#", NSStringFromCGRect(self.toolbar.frame));
}
This will print something like:
2015-05-14 00:13:46.313 ToolbarKeyboard[8367:4583306] 1 {{0, 524}, {320, 44}}
2015-05-14 00:13:46.314 ToolbarKeyboard[8367:4583306] 2 {{0, 524}, {320, 44}}
2015-05-14 00:13:46.314 ToolbarKeyboard[8367:4583306] 3 {{0, 524}, {320, 44}}
2015-05-14 00:13:46.315 ToolbarKeyboard[8367:4583306] 4 {{0, 524}, {320, 44}}
2015-05-14 00:13:46.491 ToolbarKeyboard[8367:4583306] 5 {{0, 0}, {320, 0}}
2015-05-14 00:13:46.491 ToolbarKeyboard[8367:4583306] 6 {{0, 0}, {320, 0}}
So, we discovered that, somehow, your bar height became 0. And, to be honest I don't know why, but lets continue our debugging.
As pointed by #jammycoder you don't need to the the inputView of the UITextView you only need to do that if you want a custom keyboard. So lets change our code to be like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField.delegate = self;
NSLog(#"1 %#", NSStringFromCGRect(self.toolbar.frame));
self.textField.inputAccessoryView = self.toolbar;
NSLog(#"2 %#", NSStringFromCGRect(self.toolbar.frame));
[self.toolbar removeFromSuperview];
NSLog(#"3 %#", NSStringFromCGRect(self.toolbar.frame));
[self.textField becomeFirstResponder];
}
- (void)textViewDidBeginEditing:(UITextView *)textView
{
NSLog(#"4 %#", NSStringFromCGRect(self.toolbar.frame));
self.textField.inputAccessoryView = self.toolbar;
NSLog(#"5 %#", NSStringFromCGRect(self.toolbar.frame));
}
This will print that the height of the toolbar remained unchanged. And the toolbar is being shown above the keyboard.
Until here I was using a real device to debug, decided to use a simulator. Wait, it is not opening the keyboard there! It seems to be a new feature of Xcode 6, so I did a quick search and found this stackoverflow: Xcode 6: Keyboard does not show up in simulator Did what was saying in the most voted answer and the everything is working just fine.
So, in short. The following minimum code will produce the desired behavior. And if you are using the simulator to test/debug it make sure to do what is described here: https://stackoverflow.com/a/24497773/3927536
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITextView *textField;
#property (weak, nonatomic) IBOutlet UIToolbar *toolbar;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField.inputAccessoryView = self.toolbar;
[self.textField becomeFirstResponder];
}
#end
This line brings up the keyboard
[self.textField becomeFirstResponder];
When a textfield becomes first responder it automatically brings up the keyboard.
Edit: remove the following line
self.textField.inputView = self.toolbar;
You only need to set the toolbar as inputAccessoryView
Edit2: also remove this line
[self.toolbar removeFromSuperview];
In my app I have a UITextField on the navigationController toolbar.
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic,strong) NSArray *toolBarButtonItems;
#property (nonatomic,strong) UITextField *textField;
#property (nonatomic,strong) UITextField *textField2;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
self.textField.delegate = self;
self.textField.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField];
self.toolBarButtonItems = #[flexibleSpace,barButtonItem,flexibleSpace];
self.toolbarItems = self.toolBarButtonItems;
self.navigationController.toolbar.barTintColor = [UIColor blueColor];
[self.navigationController setToolbarHidden:NO animated:NO];
}
When the textField is clicked the keyboard opens up and I create a new inputAccessoryView toolbar with another textField.
-(UIToolbar *)addToolBar{
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:self.navigationController.toolbar.frame];
toolbar.barTintColor = [UIColor darkGrayColor];
self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
self.textField2.delegate = self;
self.textField2.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField2];
[toolbar setItems:#[flexibleSpace,barButtonItem,flexibleSpace]];
return toolbar;
}
The idea is to change the firstResponder to the textField on the inputAccessoryView so this way I can see what I'm editing. The reason I am doing this is cause I can't scroll the Navigation toolbar up past the keyboard and I want to see the text that I am editing.
-(void)textFieldDidBeginEditing:(UITextField *)textField{
textField.inputAccessoryView = [self addToolBar];
if(self.textField2.isFirstResponder != NO){
[self.textField2 becomeFirstResponder];
}
}
It doesn't seem to be working when I click on the textField in the navigationController toolbar. The new inputAccessoryView toolbar shows up over the keyboard but I can't edit the field because the responder doesn't seem to be changing. The return key doesn't work either. I have to hit it twice in order to close the keyboard and when I do the text doesn't match up between the two text fields.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
self.textField.text = self.textField2.text;
return YES;
}
I got it to work like this:
#import "KJMViewController.h"
#interface KJMViewController ()
#property (strong, nonatomic) UITextField *textField1;
#property (strong, nonatomic) UITextField *textField2;
#end
#implementation KJMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField1 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
self.textField1.borderStyle = UITextBorderStyleRoundedRect;
self.textField1.delegate = self;
UIToolbar *navToolbar = self.navigationController.toolbar;
[navToolbar addSubview:self.textField1];
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
self.textField2.borderStyle = UITextBorderStyleRoundedRect;
self.textField2.delegate = self;
[toolbar addSubview:self.textField2];
self.textField1.inputAccessoryView = toolbar;
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(firstRes:) name:UIKeyboardDidShowNotification object:nil];
}
- (void)firstRes:(id)sender
{
[self.textField2 becomeFirstResponder];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.textField2) {
self.textField1.text = self.textField2.text;
}
[textField resignFirstResponder];
[self.textField1 resignFirstResponder];
return YES;
}
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter]removeObserver:self forKeyPath:UIKeyboardDidShowNotification];
[super viewDidDisappear:animated];
}
#end
Here's what's happening in viewDidLoad:
Initialise toolbar and textField2
Set the inputAccessory for textField1 (the one hidden by the keyboard) here so it's ready to become firstResponder
Then in the viewDidAppear method:
Sign up for a notification that's sent when the keyboard is shown. You'll then write some code in the "firstRes" method to make textField2 the firstResponder. You need to make it the firstResponder using this notification because you know that it's in the view hierarchy by this time, which means it's able to become firstResponder. Calling it in the -(void)textFieldDidBeginEditing:(UITextField *)textField seems to fire it before textField2 comes on screen, meaning that it can't become firstResponder. We sign up for it in the viewDidAppear method because we only want to get the notification if we're on screen.
After textField2 resignsFirstResponder, textField1 becomes first responder again, so you have to call resignFirstResponder twice in the textFieldShouldReturn method.
Also, if we leave the screen, we need to remove ourself as an observer of the keyboard notification in the viewDidDisappear method.
Here's a link to the project I made in Xcode so you can see how it works:
https://github.com/kylejm/UIToolBar-UITextView
Right now, I have basic code for moving the textfield above the keyboard when you start editing. However, the size of the textfield varies based on device and orientation. So, I wrote a crude way of doing it, which doesn't stay consistently right above the keyboard, but instead will go up further when you rotate it, and so it doesn't look as professional as I would like.
The basic sense of my question is if there is a logic for getting the size of the keyboard based on device and orientation and using that value automatically and hopefully faster than this.
If that is the best way, please let me know. Otherwise, please provide input. Here is the code that I have.
(This is just the move-up code, not the move down code, in order to prevent taking up too much space)
- (void)textFieldDidBeginEditing:(UITextField *)textField {
//Get Device Type
NSString *deviceType = [[UIDevice currentDevice] model];
//Animate Text Field
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
if ([deviceType isEqualToString:#"iPhone"]) {
//Size For iPhone
googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 210.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);
} else if ([deviceType isEqualToString:#"iPad"]) {
//Size for iPad
googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 320.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);
} else if ([deviceType isEqualToString:#"iPod touch"]) {
//Size For iPod Touch
googleBar.frame = CGRectMake(googleBar.frame.origin.x - 62.0, (googleBar.frame.origin.y - 210.0), googleBar.frame.size.width + 120.0, googleBar.frame.size.height);
}
[UIView commitAnimations];
}
What you really want to do is observe the UIKeyboard(Did|Will)(Show|Hide) notifications. They contain in their userInfo dictionaries the beginning and ending frame, as well as the correct animation curve and durations.
So after observing this notification, when it's posted move your text field based on the size of the frame passed in the notification, according to the animation hints provided.
You can see more information in the UIWindow class reference's "notifications" section: https://developer.apple.com/library/ios/#documentation/uikit/reference/UIWindow_Class/UIWindowClassReference/UIWindowClassReference.html
Below is a sample view controller implementation. The nib for this view controller was just a single text field, with an outlet connected to it, and the text field's delegate set to the view controller.
#interface ViewController ()
- (void)viewControllerInit;
#end
#implementation ViewController
#synthesize textField;
- (id)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
[self viewControllerInit];
}
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
[self viewControllerInit];
}
return self;
}
- (void)viewControllerInit
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Notification Handlers
- (void)keyboardWillShow:(NSNotification *)notification
{
// I'll try to make my text field 20 pixels above the top of the keyboard
// To do this first we need to find out where the keyboard will be.
NSValue *keyboardEndFrameValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardEndFrame = [keyboardEndFrameValue CGRectValue];
// When we move the textField up, we want to match the animation duration and curve that
// the keyboard displays. So we get those values out now
NSNumber *animationDurationNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration = [animationDurationNumber doubleValue];
NSNumber *animationCurveNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
UIViewAnimationCurve animationCurve = [animationCurveNumber intValue];
// UIView's block-based animation methods anticipate not a UIVieAnimationCurve but a UIViewAnimationOptions.
// We shift it according to the docs to get this curve.
UIViewAnimationOptions animationOptions = animationCurve << 16;
// Now we set up our animation block.
[UIView animateWithDuration:animationDuration
delay:0.0
options:animationOptions
animations:^{
// Now we just animate the text field up an amount according to the keyboard's height,
// as we mentioned above.
CGRect textFieldFrame = self.textField.frame;
textFieldFrame.origin.y = keyboardEndFrame.origin.y - textFieldFrame.size.height - 40; //I don't think the keyboard takes into account the status bar
self.textField.frame = textFieldFrame;
}
completion:^(BOOL finished) {}];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
NSNumber *animationDurationNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration = [animationDurationNumber doubleValue];
NSNumber *animationCurveNumber = [[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey];
UIViewAnimationCurve animationCurve = [animationCurveNumber intValue];
UIViewAnimationOptions animationOptions = animationCurve << 16;
[UIView animateWithDuration:animationDuration
delay:0.0
options:animationOptions
animations:^{
self.textField.frame = CGRectMake(20, 409, 280, 31); //just some hard coded value
}
completion:^(BOOL finished) {}];
}
#pragma mark - View lifecycle
- (void)viewDidUnload
{
[self setTextField:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.textField resignFirstResponder];
return YES;
}
#end
Using notification keyboard register , you can place your textfield inside a scroll and manage the content offset of scroll to turn the actual first responder above keyboard if it's neccesary.
so after register controller to keybard appear , you must to obtain the gap between keyboard origin and scroll origin relative to parent.
you must know if an specific first responder can change content offset of scroll, therefore is neccesary to know the possible bounds between keyboard origin and first responder.
by the way you need to know the gap betwen the scroll content offset and the first responder for place your first responder in specific position.
#interface MainViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIScrollView *scroll;
#end
#interface MainViewController ()
{
CGPoint scrollOffset;
}
#end
#implementation MainViewController
#synthesize scroll
-(void)viewWillAppear:(BOOL)animated
{
[[ NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillAppear:) name:UIKeyboardDidShowNotification object:nil];
[[ NSNotificationCenter defaultCenter ] addObserver:self selector:#selector(keyboardWillDisAppear:) name:UIKeyboardDidHideNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
[[ NSNotificationCenter defaultCenter ] removeObserver:self ];
}
-(void)keyboardWillAppear:(NSNotification*) note
{
const CGFloat default_gap = 25.0f;
NSValue *keyBoardEndFrameValue = [[ note userInfo ] objectForKey:UIKeyboardFrameEndUserInfoKey ];
CGRect keyBoardFrame = [ keyBoardEndFrameValue CGRectValue ];
offset = scroll.contentOffset;
UIWindow *window = [[ UIApplication sharedApplication ] keyWindow];
UITextField *textField = (UITextField*)[ window performSelector:#selector(firstResponder) ];
//Gap between keyboard origin and the scroll origin, relative to parent.
CGFloat distanceRelativeToParent = keyBoardFrame.origin.y - scroll.frame.origin.y;
//Distance between superview to textfield inside scroll. to determine if it's necesary to scroll.
CGFloat bound = (textField.frame.origin.y + textField.frame.size.height)+scroll.frame.origin.y;
CGFloat gapScroll = textField.frame.size.height+default_gap;
if( bound >= keyBoardFrame.origin.y )
{
[ UIView animateWithDuration:.3 delay:0.0 options:UIViewAnimationCurveEaseOut
animations:^{
[ scroll setContentOffset:CGPointMake(0, textField.frame.origin.y - distanceRelativeToParent + gapScroll ) animated:YES ];
}
completion:^(BOOL finished){
}];
}
}
-(void) keyboardWillDisAppear:(NSNotification*) note
{
[ scroll setContentOffset:offset animated:YES ];
}
#end
UIViewControllers have a property called interfaceOrientation and the function UIInterfaceOrientationIsPortrait/Landscape so essentially you can do:
if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation){
//portrait logic
}
else{
//landcapeLogic
}
inside for each the iPhone and iPad in your view controller. From there you can do your pixel measurement way as you had done before, because as far as I know that's the simplest way to do it.
P.S. There is a function to check for landscape checker too, but if the first if statement is false meaning the device is not in portrait, then it must be in landscape hence the plain else.
I try to build a endless scrolling UIScrollView. So far I took the apple sample "StreetScroller". So all I do is setting the contentOffset back when it reaches the end of the scroll view.
Override -layoutSubviews of the UIScrollView:
- (void)layoutSubviews
{
CGFloat contentWidth = [self contentSize].width;
CGPoint contentOffset = [self contentOffset];
CGFloat centerOffsetX = (contentWidth - [self bounds].size.width) / 2.0;
CGFloat distanceFromCenter = contentOffset.x - centerOffsetX;
if (ABS(distanceFromCenter) > (contentWidth / 4.0)) {
contentOffset = CGPointMake(centerOffsetX, contentOffset.y);
[super setContentOffset:contentOffset];
}
}
Now on iOS 5 this works like a charm. But on iOS 4.3 it's not working. As soon as I call [super setContentOffset:contentOffset] it stoops scrolling because next time -layoutSubviews get's called the [self contentOffset] does not return the contentOffset that was set.
I know there are a lot a questions about infinite UIScrollViews, but one of these has fixed this problem!
Try this One. This Code is Working Properly for me on iOS 4.3
RootViewController.h
#class ViewControllerForDuplicateEndCaps;
#interface RootViewController : UIViewController {
ViewControllerForDuplicateEndCaps *viewControllerForDuplicateEndCaps;
}
#property (nonatomic, retain) ViewControllerForDuplicateEndCaps *viewControllerForDuplicateEndCaps;
- (IBAction)loadScrollViewWithDuplicateEndCaps:(id)sender;
#end
RootViewController.m
#import "RootViewController.h"
#import "ViewControllerForDuplicateEndCaps.h"
#import "InfiniteScrollViewAppDelegate.h"
#implementation RootViewController
#synthesize viewControllerForDuplicateEndCaps;
- (IBAction)loadScrollViewWithDuplicateEndCaps:(id)sender {
InfiniteScrollViewAppDelegate *delegate = (InfiniteScrollViewAppDelegate*)[[UIApplication sharedApplication] delegate];
if(self.viewControllerForDuplicateEndCaps == nil) {
ViewControllerForDuplicateEndCaps *temp = [[ViewControllerForDuplicateEndCaps alloc] initWithNibName:#"ViewControllerForDuplicateEndCaps" bundle:nil];
self.viewControllerForDuplicateEndCaps = temp;
[temp release];
}
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[delegate.navigationController pushViewController:self.viewControllerForDuplicateEndCaps animated:YES];
}
- (void)dealloc {
[scrollView release];
[super dealloc];
}
#end
ViewControllerForDuplicateEndCaps.h
#import <UIKit/UIKit.h>
#interface ViewControllerForDuplicateEndCaps : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *scrollView;
}
#property (nonatomic, retain) UIScrollView *scrollView;
- (void)addImageWithName:(NSString*)imageString atPosition:(int)position;
#end
ViewControllerForDuplicateEndCaps.m
#import "ViewControllerForDuplicateEndCaps.h"
#implementation ViewControllerForDuplicateEndCaps
#synthesize scrollView;
- (void)viewDidLoad {
[super viewDidLoad];
// add the last image (image4) into the first position
[self addImageWithName:#"image4.jpg" atPosition:0];
// add all of the images to the scroll view
for (int i = 1; i < 5; i++) {
[self addImageWithName:[NSString stringWithFormat:#"image%i.jpg",i] atPosition:i];
}
// add the first image (image1) into the last position
[self addImageWithName:#"image1.jpg" atPosition:5];
scrollView.contentSize = CGSizeMake(1920, 416);
[scrollView scrollRectToVisible:CGRectMake(320,0,320,416) animated:NO];
}
- (void)addImageWithName:(NSString*)imageString atPosition:(int)position {
// add image to scroll view
UIImage *image = [UIImage imageNamed:imageString];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(position*320, 0, 320, 416);
[scrollView addSubview:imageView];
[imageView release];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender {
NSLog(#"%f",scrollView.contentOffset.x);
// The key is repositioning without animation
if (scrollView.contentOffset.x == 0) {
// user is scrolling to the left from image 1 to image 4
// reposition offset to show image 4 that is on the right in the scroll view
[scrollView scrollRectToVisible:CGRectMake(1280,0,320,416) animated:NO];
}
else if (scrollView.contentOffset.x == 1600) {
// user is scrolling to the right from image 4 to image 1
// reposition offset to show image 1 that is on the left in the scroll view
[scrollView scrollRectToVisible:CGRectMake(320,0,320,416) animated:NO];
}
}
- (void)dealloc {
[scrollView release];
[super dealloc];
}
#end