0

I had table view with textfields in it, when entering the text in the textfield the textfield should move automatically upward, just above the keyboard.

I had seen many solutions in the stackoverflow writing the logic in the textfield delegate methods.

I would like to share the solution for moving the textfields above the keyboard without any logic.

This post is to share the solution to all.

This solution is not same as this 'How to make a UITextField move up when keyboard is present?'

Thanks in Advance.

Community
  • 1
  • 1
Ramesh Muthe
  • 811
  • 7
  • 15
  • 3
    How can there be no logic? Something has to know how to scroll the view to move the text field. – rmaddy Nov 05 '14 at 05:12
  • The logic will be in the customtableviewcell and from there the same delegate will fire in the implemented class – Ramesh Muthe Nov 05 '14 at 05:14
  • try this (https://github.com/michaeltyson/TPKeyboardAvoiding). maybe this will help you. – ChintaN -Maddy- Ramani Nov 05 '14 at 05:14
  • 3
    So it seems your intent of this question was so you could post your own implementation as an answer. That is fine but you need to reword your question so it makes sense as a question. As it is worded now, it's confusing and no one else would know how to provide an answer. – rmaddy Nov 05 '14 at 05:16
  • Please suggest the reword, this would help all – Ramesh Muthe Nov 05 '14 at 05:17
  • Perhaps the question should be to how to write a reusable custom class which would handle all logic ? – GoodSp33d Nov 05 '14 at 05:22
  • the Customtableviewcell has the logic but in your class the textfield delegate do not need any logic. – Ramesh Muthe Nov 05 '14 at 05:23
  • Apple provide us a clue, idea and logic of implementation here => https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html (Read topic of "Moving Content That Is Located Under the Keyboard") .... i doubting about your try of searching. – Tirth Nov 05 '14 at 05:26

2 Answers2

2

I use LHSKeyboardAdjusting, which does not tie up your UITextField delegate methods. A lot of libraries will take over your delegates so you can't do things like advance to the next text field when -[UITextFieldDelegate textFieldShouldReturn:] is fired.

LHSKeyboardAdjusting listens to keyboard show/hide events and adjusts the bottom constraint of the view that you pass in. The cool thing is this works with UIView and UIScrollView.

In your UIViewController subclass, this is how you set it up (in this case, I am using a UIScrollView in a xib or storyboard):

#import "UIViewControllerSubclass.h"
#import <LHSKeyboardAdjusting/UIViewController+LHSKeyboardAdjustment.h>

@interface UIViewControllerSubclass () <LHSKeyboardAdjusting>

@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;

/** The constraint that anchors '_scrollView' bottom to '_view' bottom */
@property (nonatomic, weak) IBOutlet NSLayoutConstraint *scrollViewBottomConstraint;

@end

@implementation UIViewControllerSubclass

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [self lhs_activateKeyboardAdjustment];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    [self lhs_deactivateKeyboardAdjustment];
}

#pragma mark - LHSKeyboardAdjusting

- (NSLayoutConstraint *)keyboardAdjustingBottomConstraint {
    return self.scrollViewBottomConstraint;
}

@end
Jeff
  • 349
  • 2
  • 12
0

The below are customcell file //.h file

#import <UIKit/UIKit.h>
@protocol TextFieldScrollToVisibleDelegate
@optional
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
- (void)textFieldDidBeginEditing:(UITextField *)textField;
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
- (void)textFieldDidEndEditing:(UITextField *)textField;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
- (BOOL)textFieldShouldClear:(UITextField *)textField;
- (BOOL)textFieldShouldReturn:(UITextField *)textField;


- (BOOL)textViewShouldBeginEditing:(UITextView *)textView;
- (BOOL)textViewShouldEndEditing:(UITextView *)textView;

- (void)textViewDidBeginEditing:(UITextView *)textView;
- (void)textViewDidEndEditing:(UITextView *)textView;

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)textViewDidChange:(UITextView *)textView;

- (void)textViewDidChangeSelection:(UITextView *)textView;

@end
@interface CustomTableViewCell : UITableViewCell <UITextFieldDelegate,UITextViewDelegate>
@property (nonatomic, assign) NSObject <TextFieldScrollToVisibleDelegate> *mTextFieldScrollToVisibleDelegate_;
@property (nonatomic)  int paddingabovekeyboard;
@end

//.m file

#import "CustomTableViewCell.h"
@interface CustomTableViewCell ()
@property (nonatomic)int keyboardHeight;
@property (nonatomic)BOOL useSecondMode;
@property (nonatomic)int actualViewHeight;
@property (nonatomic)int actualViewWidth;
@property (nonatomic)int previousYposition;
@end
#define kKeyboardHeightValue (keyboardHeight==0)?250:keyboardHeight
@implementation CustomTableViewCell
@synthesize mTextFieldScrollToVisibleDelegate_;
@synthesize paddingabovekeyboard;

@synthesize keyboardHeight;
@synthesize useSecondMode;
@synthesize actualViewHeight;
@synthesize actualViewWidth;
@synthesize previousYposition;

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        paddingabovekeyboard=50;
    }
    return self;
}
-(void)wheatherFirstModeOrsecondMode {
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    BOOL statusBarHidden = [UIApplication sharedApplication].statusBarHidden;
    int statusHight= 20;
    if(statusBarHidden) {
        statusHight=0;
    }
    int navheight=0;
    id nav = [UIApplication sharedApplication].keyWindow.rootViewController;
    if ([nav isKindOfClass:[UINavigationController class]]) {
        UINavigationController *navc = (UINavigationController *) nav;
        if(!navc.navigationBarHidden) {
            navheight=44;
        }
    }
    if(UI_USER_INTERFACE_IDIOM () ==UIUserInterfaceIdiomPhone )
    {
        if(orientation == 0||orientation == UIInterfaceOrientationPortrait) {
            keyboardHeight = 216+paddingabovekeyboard; //44
            actualViewHeight= [[UIScreen mainScreen]bounds].size.height-statusHight-navheight;
            actualViewWidth =[[UIScreen mainScreen]bounds].size.width;
        }  else if(orientation == UIInterfaceOrientationLandscapeLeft||orientation == UIInterfaceOrientationLandscapeRight) {
            keyboardHeight = 162+paddingabovekeyboard; //444
            actualViewHeight= [[UIScreen mainScreen]bounds].size.width-statusHight-navheight;
            actualViewWidth =[[UIScreen mainScreen]bounds].size.height;
        }
    } else if (UI_USER_INTERFACE_IDIOM () == UIUserInterfaceIdiomPad){
        if(orientation == 0||orientation == UIInterfaceOrientationPortrait) {
            keyboardHeight = 264+paddingabovekeyboard; //44
            actualViewHeight= [[UIScreen mainScreen]bounds].size.height-statusHight-navheight;
            actualViewWidth =[[UIScreen mainScreen]bounds].size.width;

        }  else if(orientation == UIInterfaceOrientationLandscapeLeft||orientation == UIInterfaceOrientationLandscapeRight) {
            keyboardHeight = 352+paddingabovekeyboard;//44
            actualViewHeight= [[UIScreen mainScreen]bounds].size.width-statusHight-navheight;
            actualViewWidth =[[UIScreen mainScreen]bounds].size.height;

        }
    }
    UITableView *myTableView = (UITableView *)[self superview];
    if(![myTableView isKindOfClass:[UITableView class]]) {
        myTableView = (UITableView *)[[self superview] superview];
    }
    if(![myTableView isKindOfClass:[UITableView class]]) {
        myTableView = (UITableView *)[[[self superview] superview] superview];
    }
    NSLog(@"keyboardHeight %dactualViewHeight%d",keyboardHeight,actualViewHeight);
    if(myTableView.frame.origin.y>actualViewHeight-keyboardHeight-50) {
        useSecondMode=TRUE;
    } else {
        useSecondMode=FALSE;
    }
#undef kKeyboardHeightValue
#define kKeyboardHeightValue (keyboardHeight==0)?250:keyboardHeight
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
    @try {
        UITableView *myTableView = (UITableView *)[self superview];
        if(![myTableView isKindOfClass:[UITableView class]]) {
            myTableView = (UITableView *)[[self superview] superview];
        }
        if(![myTableView isKindOfClass:[UITableView class]]) {
            myTableView = (UITableView *)[[[self superview] superview] superview];
        }
        int scrollpadding;
        if(!self.useSecondMode) {
            scrollpadding=actualViewHeight - (myTableView.frame.origin.y+myTableView.frame.size.height);
            scrollpadding = kKeyboardHeightValue-scrollpadding;
        } else {
            CGRect lframe= myTableView.superview.frame;
            self.previousYposition=myTableView.superview.frame.origin.y;

            int heighttochange=0;
            if(myTableView.frame.origin.y<myTableView.frame.size.height) {
                heighttochange = myTableView.frame.size.height;
            } else {
                heighttochange = myTableView.frame.origin.y;

            }
            int temp = actualViewHeight- keyboardHeight;
            temp = self.frame.origin.y - temp+50;
            heighttochange = (heighttochange>temp)?temp:heighttochange;
            lframe.origin.y-=heighttochange;
            self.superview.frame=lframe;

            scrollpadding =actualViewHeight - ((myTableView.frame.origin.y+lframe.origin.y)+myTableView.frame.size.height);
            scrollpadding = kKeyboardHeightValue-scrollpadding;
        }

        UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, scrollpadding, 0.0);
        myTableView.contentInset = contentInsets;
        myTableView.scrollIndicatorInsets = contentInsets;
        CGRect lFrame=[myTableView convertRect:textField.bounds fromView:textField];
        [myTableView scrollRectToVisible:lFrame animated:NO];

        if (nil != mTextFieldScrollToVisibleDelegate_ && [mTextFieldScrollToVisibleDelegate_ respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
            [mTextFieldScrollToVisibleDelegate_ textFieldDidBeginEditing:textField];
        }
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    @try {
        UITableView *myTableView = (UITableView *)[self superview];
        if(![myTableView isKindOfClass:[UITableView class]]) {
            myTableView = (UITableView *)[[self superview] superview];
        }
        if(![myTableView isKindOfClass:[UITableView class]]) {
            myTableView = (UITableView *)[[[self superview] superview] superview];
        }

        if(!useSecondMode) {
            UIEdgeInsets contentInsets = UIEdgeInsetsZero;
            myTableView.contentInset = contentInsets;
            myTableView.scrollIndicatorInsets = contentInsets;
        } else {
            CGRect lframe= self.superview.frame;
            lframe.origin.y=self.previousYposition;
            self.superview.frame=lframe;
            UIEdgeInsets contentInsets = UIEdgeInsetsZero;
            myTableView.contentInset = contentInsets;
            myTableView.scrollIndicatorInsets = contentInsets;
        }
        if (nil != mTextFieldScrollToVisibleDelegate_ && [mTextFieldScrollToVisibleDelegate_ respondsToSelector:@selector(textFieldDidEndEditing:)]) {
            [mTextFieldScrollToVisibleDelegate_ textFieldDidEndEditing:textField];
        }
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    @try {
        UITableView *myTableView = (UITableView *)[self superview];
        if(![myTableView isKindOfClass:[UITableView class]]) {
            myTableView = (UITableView *)[[self superview] superview];
        }
        if(![myTableView isKindOfClass:[UITableView class]]) {
            myTableView = (UITableView *)[[[self superview] superview] superview];
        }
        UITableViewCell *cell =((UITableViewCell*)[[textField superview] superview]);
        if(![cell isKindOfClass:[UITableViewCell class]]) {
            cell = (UITableViewCell *)[[[textField superview]superview] superview];
        }
        if(!useSecondMode) {
            UIEdgeInsets contentInsets = UIEdgeInsetsZero;
            myTableView.contentInset = contentInsets;
            myTableView.scrollIndicatorInsets = contentInsets;
        } else {
            CGRect lframe= self.superview.frame;
            lframe.origin.y=self.previousYposition;
            self.superview.frame=lframe;
            UIEdgeInsets contentInsets = UIEdgeInsetsZero;
            myTableView.contentInset = contentInsets;
            myTableView.scrollIndicatorInsets = contentInsets;
        }
        [textField resignFirstResponder];

        if (nil != mTextFieldScrollToVisibleDelegate_ && [mTextFieldScrollToVisibleDelegate_ respondsToSelector:@selector(textFieldShouldReturn:)]) {
            return [mTextFieldScrollToVisibleDelegate_ textFieldShouldReturn:textField];
        }
        return YES;
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    if (nil != mTextFieldScrollToVisibleDelegate_ && [mTextFieldScrollToVisibleDelegate_ respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
        return [mTextFieldScrollToVisibleDelegate_ textFieldShouldEndEditing:textField];
    }
    return YES;
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
    [self wheatherFirstModeOrsecondMode];

    if (nil != mTextFieldScrollToVisibleDelegate_ && [mTextFieldScrollToVisibleDelegate_ respondsToSelector:@selector(textFieldShouldBeginEditing:)]) {
        return [mTextFieldScrollToVisibleDelegate_ textFieldShouldBeginEditing:textField];
    }
    return YES;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    if (nil != mTextFieldScrollToVisibleDelegate_ && [mTextFieldScrollToVisibleDelegate_ respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
        return [mTextFieldScrollToVisibleDelegate_ textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    return YES;
}

@end

Add the above two custom cell files to your project

Now the below is how to implement

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        UITextField *ltext = [[UITextField alloc] initWithFrame:CGRectMake(10, 2, 120, 30)];
        ltext.borderStyle = UITextBorderStyleLine;
        ltext.delegate=cell;
        cell.mTextFieldScrollToVisibleDelegate_=self;
        ltext.tag=1;
        [cell.contentView addSubview:ltext];

    }
    cell.paddingabovekeyboard=44;

    return cell;
}

Explanation for the above code Use CustomTableViewCell instead of UITableViewCell.

Note: this code works only for textfields in the tableview

Ramesh Muthe
  • 811
  • 7
  • 15