ios - टेक्स्ट फ़ील्ड का चयन करते समय UITableView स्क्रॉल बनाना




iphone keyboard scroll (25)

Very interesting discussion thread, i also faced the same problem may be worse one because

  1. I was using a custom cell and the textfield was inside that.
  2. I had to use UIViewController to meet my requirements so cant take advantage of UITableViewController.
  3. I had filter/ sort criterias in my table cell, ie ur cells keeps on changing and keeping track of the indexpath and all will not help.

So read the threads here and implemented my version, which helped me in pushing up my contents in iPad in landscape mode. Here is code ( this is not fool proof and all, but it fixed my issue) First u need to have a delegate in your custom cell class, which on editing begins, sends the textfield to ur viewcontroller and set the activefield = theTextField there

// IMPLEMENTED TO HANDLE LANDSCAPE MODE ONLY

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect aRect = myTable.frame;

    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);

    aRect.size.height -= kbSize.height+50;
// This will the exact rect in which your textfield is present
        CGRect rect =  [myTable convertRect:activeField.bounds fromView:activeField];
// Scroll up only if required
    if (!CGRectContainsPoint(aRect, rect.origin) ) {


            [myTable setContentOffset:CGPointMake(0.0, rect.origin.y) animated:YES];

    }


}

// Called when the UIKeyboardWillHideNotification is sent

- (void)keyboardWillHide:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    myTable.contentInset = contentInsets;
    myTable.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbValue = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGSize kbSize = CGSizeMake(kbValue.height, kbValue.width);
    CGRect bkgndRect = activeField.superview.frame;
    bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [myTable setContentOffset:CGPointMake(0.0, 10.0) animated:YES];
}

-anoop4real

बहुत सारे परीक्षण और त्रुटि के बाद, मैं हार मान रहा हूं और सवाल पूछ रहा हूं। मैंने इसी तरह की समस्याओं के साथ बहुत से लोगों को देखा है लेकिन सही काम करने के लिए सभी जवाब नहीं मिल सकते हैं।

मेरे पास UITableView जो कस्टम सेल से बना है। कोशिकाएं एक दूसरे के बगल में 5 टेक्स्ट फ़ील्ड से बने होते हैं (जैसे ग्रिड की तरह)।

जब मैं UITableView के नीचे कक्षों को स्क्रॉल और संपादित करने का प्रयास करता हूं, तो मैं अपने कक्षों को कीबोर्ड से ऊपर ठीक से स्थानांतरित करने का प्रबंधन नहीं कर सकता।

मैंने दृश्य आकार बदलने आदि के बारे में कई जवाब देखे हैं ... लेकिन उनमें से कोई भी अब तक अच्छी तरह से काम नहीं कर पाया है।

क्या कोई ठोस कोड उदाहरण के साथ ऐसा करने के "सही" तरीके को स्पष्ट कर सकता है?


Another easy method (only works with one section)

//cellForRowAtIndexPath
UItextField *tf;
[cell addSubview:tf];
tf.tag = indexPath.row;
tf.delegate = self;

//textFieldDidBeginEditing:(UITextField *)text
[[self.tableView scrollToRowsAtIndexPath:[NSIndexPath indexPathForRow:text.tag in section:SECTIONINTEGER] animated:YES];

यदि आप UITableViewController उपयोग कर सकते हैं, तो आप कार्यक्षमता को मुफ्त में प्राप्त कर सकते हैं। कभी-कभी, हालांकि, यह एक विकल्प नहीं है, विशेष रूप से यदि आपको केवल UITableView न केवल एकाधिक दृश्यों की आवश्यकता है।

यहां प्रस्तुत कुछ समाधान आईओएस ≥4 पर काम नहीं करते हैं, कुछ आईपैड या लैंडस्केप मोड में काम नहीं करते हैं, कुछ ब्लूटूथ कीबोर्ड (जहां हम कोई स्क्रॉलिंग नहीं चाहते हैं) के लिए काम नहीं करते हैं, कुछ नहीं करते हैं एकाधिक टेक्स्ट फ़ील्ड के बीच स्विच करते समय काम करें। तो यदि आप कोई समाधान चुनते हैं, तो इन मामलों का परीक्षण करना सुनिश्चित करें। यह वह समाधान है जिसका उपयोग हम InAppSettingsKit में उपयोग करते हैं :

- (void)_keyboardWillShow:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
        NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
        if (!keyboardFrameValue) {
            keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
        }

        // Reduce the tableView height by the part of the keyboard that actually covers the tableView
        CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            windowRect = IASKCGRectSwap(windowRect);
        }
        CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
        if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
            viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        }
        CGRect frame = _tableView.frame;
        frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = frame;
        [UIView commitAnimations];

        UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
        NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

        // iOS 3 sends hide and show notifications right after each other
        // when switching between textFields, so cancel -scrollToOldPosition requests
        [NSObject cancelPreviousPerformRequestsWithTarget:self];

        [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
    }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)_keyboardWillHide:(NSNotification*)notification {
    if (self.navigationController.topViewController == self) {
        NSDictionary* userInfo = [notification userInfo];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
        _tableView.frame = self.view.bounds;
        [UIView commitAnimations];

        [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
    }
}   

InAppSettingsKit में कक्षा का पूरा कोड यहां दिया गया है। इसका परीक्षण करने के लिए, "पूर्ण सूची" बाल फलक का उपयोग करें जहां आप ऊपर वर्णित परिदृश्यों का परीक्षण कर सकते हैं।


This soluton works for me, PLEASE note the line

[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];

You can change the 160 value to match it work with you

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
                        bkgndRect.size.height += kbSize.height;
     [activeField.superview setFrame:bkgndRect];
     [tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
   activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
 {
     activeField = nil;
 }
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    tableView.contentInset = contentInsets;
    tableView.scrollIndicatorInsets = contentInsets;
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    CGRect bkgndRect = activeField.superview.frame;
    //bkgndRect.size.height += kbSize.height;
    [activeField.superview setFrame:bkgndRect];
    [tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];
}

स्क्रॉलिंग करने वाला फ़ंक्शन बहुत आसान हो सकता है:

- (void) textFieldDidBeginEditing:(UITextField *)textField {
    UITableViewCell *cell;

    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
    // Load resources for iOS 6.1 or earlier
        cell = (UITableViewCell *) textField.superview.superview;

    } else {
        // Load resources for iOS 7 or later
        cell = (UITableViewCell *) textField.superview.superview.superview; 
       // TextField -> UITableVieCellContentView -> (in iOS 7!)ScrollView -> Cell!
    }
    [tView scrollToRowAtIndexPath:[tView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

बस। बिल्कुल कोई गणना नहीं।


Since you have textfields in a table, the best way really is to resize the table - you need to set the tableView.frame to be smaller in height by the size of the keyboard (I think around 165 pixels) and then expand it again when the keyboard is dismissed.

You can optionally also disable user interaction for the tableView at that time as well, if you do not want the user scrolling.


I hope you guys already got a solution reading all those. But I found my solution as follows. I am expecting that you already have a cell with UITextField . So on preparing just keep the row index into the text field's tag.

cell.textField.tag = IndexPath.row;

Create an activeTextField , instance of UITextField with global scope as below:

@interface EditViewController (){

    UITextField *activeTextField;

}

So, now you just copy paste my code at the end. And also don't forget to add UITextFieldDelegate

#pragma mark - TextField Delegation

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{

    activeTextField = textField;

    return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField{

    activeTextField = nil;

}

Registers keyboard notifications

#pragma mark - Keyboard Activity

- (void)registerForKeyboardNotifications

{

    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWasShown:)

                                             name:UIKeyboardDidShowNotification object:nil];



    [[NSNotificationCenter defaultCenter] addObserver:self

                                         selector:@selector(keyboardWillBeHidden:)

                                             name:UIKeyboardWillHideNotification object:nil];



}

Handles Keyboard Notifications :

Called when the UIKeyboardDidShowNotification is sent.

- (void)keyboardWasShown:(NSNotification*)aNotification

{

    NSDictionary* info = [aNotification userInfo];

    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

    NSIndexPath *currentRowIndex = [NSIndexPath indexPathForRow:activeTextField.tag inSection:0];

    [self.tableView scrollToRowAtIndexPath:currentRowIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

}

Called when the UIKeyboardWillHideNotification is sent

- (void)keyboardWillBeHidden:(NSNotification*)aNotification

{

    UIEdgeInsets contentInsets = UIEdgeInsetsZero;

    [self.tableView setContentInset:contentInsets];

    [self.tableView setScrollIndicatorInsets:contentInsets];

}

Now one thing is left, Call the registerForKeyboardNotifications method in to ViewDidLoad method as follows:

- (void)viewDidLoad {

    [super viewDidLoad];

    // Registering keyboard notification

    [self registerForKeyboardNotifications];

    // Your codes here...

}

You are done, hope your textFields will no longer hidden by the keyboard.


I tried almost the same approach and came up with a simpler and smaller code for the same. I created a IBOutlet iTextView and associated with the UITextView in the IB.

 -(void)keyboardWillShow:(NSNotification *)notification
    {
        NSLog(@"Keyboard");
        CGRect keyFrame = [[[notification userInfo]objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];

        [UIView beginAnimations:@"resize view" context:nil];
        [UIView setAnimationCurve:1];
        [UIView setAnimationDuration:1.0];
        CGRect frame = iTableView.frame;
        frame.size.height = frame.size.height -  keyFrame.size.height;
        iTableView.frame = frame;
        [iTableView scrollRectToVisible:frame animated:YES];
        [UIView commitAnimations];

    }

Here is how I made this work, which is a mixture of Sam Ho and Marcel W's answers, and some of my own bug fixes made to my crappy code. I was using a UITableViewController. The table now resizes correctly when the keyboard is shown.

1) In viewDidLoad I added:

self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

2) I had forgotten to call the super equivalents in viewWillAppear and awakeFromNib . I added these back in.


Keyboard notifications work, but Apple's sample code for that assumes that the scroll view is the root view of the window. This is usually not the case. You have to compensate for tab bars, etc., to get the right offset.

It is easier than it sounds. Here is the code I use in a UITableViewController. It has two instance variables, hiddenRect and keyboardShown.

// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification {
    if (keyboardShown)
        return;

    NSDictionary* info = [aNotification userInfo];

    // Get the frame of the keyboard.
    NSValue *centerValue = [info objectForKey:UIKeyboardCenterEndUserInfoKey];
    NSValue *boundsValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
    CGPoint keyboardCenter = [centerValue CGPointValue];
    CGRect keyboardBounds = [boundsValue CGRectValue];
    CGPoint keyboardOrigin = CGPointMake(keyboardCenter.x - keyboardBounds.size.width / 2.0,
                                         keyboardCenter.y - keyboardBounds.size.height / 2.0);
    CGRect keyboardScreenFrame = { keyboardOrigin, keyboardBounds.size };


    // Resize the scroll view.
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = scrollView.frame;
    CGRect keyboardFrame = [scrollView.superview convertRect:keyboardScreenFrame fromView:nil];
    hiddenRect = CGRectIntersection(viewFrame, keyboardFrame);

    CGRect remainder, slice;
    CGRectDivide(viewFrame, &slice, &remainder, CGRectGetHeight(hiddenRect), CGRectMaxYEdge);
    scrollView.frame = remainder;

    // Scroll the active text field into view.
    CGRect textFieldRect = [/* selected cell */ frame];
    [scrollView scrollRectToVisible:textFieldRect animated:YES];

    keyboardShown = YES;
}


// Called when the UIKeyboardDidHideNotification is sent
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
    // Reset the height of the scroll view to its original value
    UIScrollView *scrollView = (UIScrollView *) self.tableView;
    CGRect viewFrame = [scrollView frame];
    scrollView.frame = CGRectUnion(viewFrame, hiddenRect);

    keyboardShown = NO;
}

If your UITableView is managed by a subclass of UITableViewController and not UITableView, and the text field delegate is the UITableViewController, it should manage all the scrolling automatically -- all these other comments are very difficult to implement in practice.

For a good example see the apple example code project: TaggedLocations.

You can see that it scrolls automatically, but there doesn't seem to be any code that does this. This project also has custom table view cells, so if you build your application with it as a guide, you should get the desired result.


THE RIGHT ANSWER is Sam Ho's answer:

"If you use UITableViewController instead of UIViewController, it will automatically do so.".

Just make sure to connect your UITableView to the TableView property of the UITableViewController (so eg do not add it as a subview of the View property of the UITableViewController).

Also make sure to set the AutoresizingMask property of your UITableView to FlexibleHeight


यदि आप UIViewController के बजाय UITableViewController का उपयोग करते हैं, तो यह स्वचालित रूप से ऐसा करेगा।


If you use Three20 , then use the autoresizesForKeyboard property. Just set in the your view controller's -initWithNibName:bundle method

self.autoresizesForKeyboard = YES

This takes care of:

  1. Listening for keyboard notifications and adjusting the table view's frame
  2. Scrolling to the first responder

Done and done.


मैं कुछ ऐसा ही कर रहा हूं जो सामान्य है, आपके कोड के लिए विशिष्ट कुछ गणना करने की आवश्यकता नहीं है। बस कोड पर टिप्पणी की जांच करें:

MyUIViewController.h में

@interface MyUIViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
{
     UITableView *myTableView;
     UITextField *actifText;
}

@property (nonatomic, retain) IBOutlet UITableView *myTableView;
@property (nonatomic, retain) IBOutlet UITextField *actifText;

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField;
- (IBAction)textFieldDidEndEditing:(UITextField *)textField;

-(void) keyboardWillHide:(NSNotification *)note;
-(void) keyboardWillShow:(NSNotification *)note;

@end

MyUIViewController.m में

@implementation MyUIViewController

@synthesize myTableView;
@synthesize actifText;

- (void)viewDidLoad 
{
    // Register notification when the keyboard will be show
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillShow:)
                                          name:UIKeyboardWillShowNotification
                                          object:nil];

    // Register notification when the keyboard will be hide
    [[NSNotificationCenter defaultCenter] addObserver:self
                                          selector:@selector(keyboardWillHide:)
                                          name:UIKeyboardWillHideNotification
                                          object:nil];
}

// To be link with your TextField event "Editing Did Begin"
//  memoryze the current TextField
- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.actifText = textField;
}

// To be link with your TextField event "Editing Did End"
//  release current TextField
- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.actifText = nil;
}

-(void) keyboardWillShow:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    // Start animation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Reduce size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height -= keyboardBounds.size.height;
    else 
        frame.size.height -= keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    // Scroll the table view to see the TextField just above the keyboard
    if (self.actifText)
      {
        CGRect textFieldRect = [self.myTableView convertRect:self.actifText.bounds fromView:self.actifText];
        [self.myTableView scrollRectToVisible:textFieldRect animated:NO];
      }

    [UIView commitAnimations];
}

-(void) keyboardWillHide:(NSNotification *)note
{
    // Get the keyboard size
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue: &keyboardBounds];

    // Detect orientation
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect frame = self.myTableView.frame;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView setAnimationDuration:0.3f];

    // Increase size of the Table view 
    if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)
        frame.size.height += keyboardBounds.size.height;
    else 
        frame.size.height += keyboardBounds.size.width;

    // Apply new size of table view
    self.myTableView.frame = frame;

    [UIView commitAnimations];
}

@end

स्विफ्ट 1.2+ संस्करण:

class ViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var activeText: UITextField!
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        activeText = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        activeText = nil
    }

    func keyboardWillShow(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height -= keyboardSize.height
            tableView.frame = frame
            if activeText != nil {
                let rect = tableView.convertRect(activeText.bounds, fromView: activeText)
                tableView.scrollRectToVisible(rect, animated: false)
            }
            UIView.commitAnimations()
        }
    }

    func keyboardWillHide(note: NSNotification) {
        if let keyboardSize = (note.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            var frame = tableView.frame
            UIView.beginAnimations(nil, context: nil)
            UIView.setAnimationBeginsFromCurrentState(true)
            UIView.setAnimationDuration(0.3)
            frame.size.height += keyboardSize.height
            tableView.frame = frame
            UIView.commitAnimations()
        }
    }
}

So after hours of grueling work trying to use these current solutions (and utterly failing) I finally got things working well, and updated them to use the new animation blocks. My answer is entirely based on Ortwin's answer above .

So for whatever reason the code above was just not working for me. My setup seemed fairly similar to others, but maybe because I was on an iPad or 4.3... no idea. It was doing some wacky math and shooting my tableview off the screen.

See end result of my solution: http://screencast.com/t/hjBCuRrPC (Please ignore the photo. :-P)

So I went with the gist of what Ortwin was doing, but changed how it was doing some math to add up the origin.y & size.height of my table view with the height of the keyboard. When I subtract the height of the window from that result , it tells me how much intersection I have going on. If its greater than 0 (aka there is some overlap) I perform the animation of the frame height.

In addition there were some redraw issues that were solved by 1) Waiting to scroll to the cell until the animation was done and 2) using the UIViewAnimationOptionBeginFromCurrentState option when hiding the keyboard.

A couple things to note.

  • _topmostRowBeforeKeyboardWasShown & _originalFrame are instance variables declared in the header.
  • self.guestEntryTableView is my tableView (I'm in an external file)
  • IASKCGRectSwap is Ortwin's method for flipping the coordinates of a frame
  • I only update the height of the tableView if at least 50px of it is going to be showing
  • Since I'm not in a UIViewController I don't have self.view, so I just return the tableView to its original frame

Again, I wouldn't have gotten near this answer if I Ortwin didn't provide the crux of it. Here's the code:

- (IBAction)textFieldDidBeginEditing:(UITextField *)textField
{
    self.activeTextField = textField;

    if ([self.guestEntryTableView indexPathsForVisibleRows].count) {
        _topmostRowBeforeKeyboardWasShown = (NSIndexPath*)[[self.guestEntryTableView indexPathsForVisibleRows] objectAtIndex:0];
    } else {
        // this should never happen
        _topmostRowBeforeKeyboardWasShown = [NSIndexPath indexPathForRow:0 inSection:0];
        [textField resignFirstResponder];
    }
}

- (IBAction)textFieldDidEndEditing:(UITextField *)textField
{
    self.activeTextField = nil;
}

- (void)keyboardWillShow:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];

    NSValue* keyboardFrameValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [self.guestEntryTableView convertRect:self.guestEntryTableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    if (UIInterfaceOrientationLandscapeLeft == orientation ||UIInterfaceOrientationLandscapeRight == orientation ) {
        windowRect = IASKCGRectSwap(windowRect);
        viewRectAbsolute = IASKCGRectSwap(viewRectAbsolute);
        keyboardFrame = IASKCGRectSwap(keyboardFrame);
    }

    // fix the coordinates of our rect to have a top left origin 0,0
    viewRectAbsolute = FixOriginRotation(viewRectAbsolute, orientation, windowRect.size.width, windowRect.size.height);

    CGRect frame = self.guestEntryTableView.frame;
    _originalFrame = self.guestEntryTableView.frame;

    int remainder = (viewRectAbsolute.origin.y + viewRectAbsolute.size.height + keyboardFrame.size.height) - windowRect.size.height;

    if (remainder > 0 && !(remainder > frame.size.height + 50)) {
        frame.size.height = frame.size.height - remainder;
        float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        [UIView animateWithDuration: duration
                        animations:^{
                            self.guestEntryTableView.frame = frame;
                        }
                        completion:^(BOOL finished){
                            UITableViewCell *textFieldCell = (UITableViewCell*) [[self.activeTextField superview] superview];
                            NSIndexPath *textFieldIndexPath = [self.guestEntryTableView indexPathForCell:textFieldCell];
                            [self.guestEntryTableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
                        }];
    }

}

- (void)keyboardWillHide:(NSNotification*)notification {
    NSDictionary* userInfo = [notification userInfo];
    float duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    [UIView animateWithDuration: duration
                          delay: 0.0
                        options: (UIViewAnimationOptionBeginFromCurrentState)
                     animations:^{
                         self.guestEntryTableView.frame = _originalFrame;
                     }
                     completion:^(BOOL finished){
                         [self.guestEntryTableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
                     }];

}   

#pragma mark CGRect Utility function
CGRect IASKCGRectSwap(CGRect rect) {
    CGRect newRect;
    newRect.origin.x = rect.origin.y;
    newRect.origin.y = rect.origin.x;
    newRect.size.width = rect.size.height;
    newRect.size.height = rect.size.width;
    return newRect;
}

CGRect FixOriginRotation(CGRect rect, UIInterfaceOrientation orientation, int parentWidth, int parentHeight) {
    CGRect newRect;
    switch(orientation)
    {
        case UIInterfaceOrientationLandscapeLeft:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), rect.origin.y, rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationLandscapeRight:
            newRect = CGRectMake(rect.origin.x, parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
            break;
        case UIInterfaceOrientationPortrait:
            newRect = rect;
            break;
        case UIInterfaceOrientationPortraitUpsideDown:
            newRect = CGRectMake(parentWidth - (rect.size.width + rect.origin.x), parentHeight - (rect.size.height + rect.origin.y), rect.size.width, rect.size.height);
            break;
    }
    return newRect;
}

स्विफ्ट के लिए सबसे आसान समाधान:

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar?.becomeFirstResponder()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow(_:)), name: UIKeyboardDidShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name: UIKeyboardDidHideNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
            tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    UIView.animateWithDuration(0.2, animations: { self.table_create_issue.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) })
    // For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
    }

मुझे लगता है कि मैं ऐप्पल के ऐप्स के व्यवहार से मेल खाने के लिए समाधान के साथ आया हूं।

सबसे पहले, आपके विचार में WillAppear: कीबोर्ड अधिसूचनाओं की सदस्यता लें, इसलिए आपको पता चलेगा कि कीबोर्ड कब दिखाएगा और छुपाएगा, और सिस्टम आपको कीबोर्ड का आकार बताएगा, लेकिन 'अपने दृश्य में पंजीकरण रद्द करने के लिए भूल जाओ'।

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillShow:)
           name:UIKeyboardWillShowNotification
         object:nil];
[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(keyboardWillHide:)
           name:UIKeyboardWillHideNotification
         object:nil];

कीबोर्ड के एक बार दिखाए जाने के बाद दृश्यमान क्षेत्र से मिलान करने के लिए नीचे दी गई विधियों को कार्यान्वित करें ताकि आप अपनी तालिका के आकार को समायोजित कर सकें। यहां मैं कीबोर्ड की स्थिति को अलग से ट्रैक कर रहा हूं, इसलिए मैं तालिका को सेट करने का चयन कर सकता हूं, मुझे पूर्ण ऊंचाई पर वापस देखें, क्योंकि आपको इन फ़ील्ड परिवर्तनों पर इन अधिसूचनाएं मिलती हैं। कीबोर्ड WillHide को लागू करना न भूलें: और अपनी तालिका दृश्य आकार को ठीक करने के लिए कहीं भी उपयुक्त चुनें।

-(void) keyboardWillShow:(NSNotification *)note
{
    CGRect keyboardBounds;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
    keyboardHeight = keyboardBounds.size.height;
    if (keyboardIsShowing == NO)
    {
        keyboardIsShowing = YES;
        CGRect frame = self.view.frame;
        frame.size.height -= keyboardHeight;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationDuration:0.3f];
        self.view.frame = frame;
        [UIView commitAnimations];
    }
}

अब यहां स्क्रॉलिंग बिट है, हम पहले कुछ आकारों को काम करते हैं, फिर हम देखते हैं कि हम दृश्य क्षेत्र में कहां हैं, और उस रेक्ट को सेट करें जिसे हम स्क्रॉल करना चाहते हैं ताकि टेक्स्ट फ़ील्ड के मध्य के ऊपर या नीचे आधा दृश्य हो जहां यह विचार में है। इस मामले में, हमारे पास UITextFields और एक enum की एक सरणी है जो उनका ट्रैक रखती है, इसलिए पंक्ति संख्या से पंक्ति को बढ़ाकर हमें इस बाहरी दृश्य के भीतर फ्रेम का वास्तविक ऑफसेट मिलता है।

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGRect frame = textField.frame;
    CGFloat rowHeight = self.tableView.rowHeight;
    if (textField == textFields[CELL_FIELD_ONE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_ONE;
    }
    else if (textField == textFields[CELL_FIELD_TWO])
    {
        frame.origin.y += rowHeight * CELL_FIELD_TWO;
    }
    else if (textField == textFields[CELL_FIELD_THREE])
    {
        frame.origin.y += rowHeight * CELL_FIELD_THREE;
    }
    else if (textField == textFields[CELL_FIELD_FOUR])
    {
        frame.origin.y += rowHeight * CELL_FIELD_FOUR;
    }
    CGFloat viewHeight = self.tableView.frame.size.height;
    CGFloat halfHeight = viewHeight / 2;
    CGFloat midpoint = frame.origin.y + (textField.frame.size.height / 2);
    if (midpoint < halfHeight)
    {
        frame.origin.y = 0;
        frame.size.height = midpoint;
    }
    else
    {
        frame.origin.y = midpoint;
        frame.size.height = midpoint;
    }
    [self.tableView scrollRectToVisible:frame animated:YES];
}

ऐसा लगता है कि यह काफी अच्छी तरह से काम करता है।


कई उत्तरों (विशेष रूप से ऑर्टविन जेन्ट्ज़, उपयोगकर्ता 98013) और रिक्त स्थान में रिक्त स्थान भरना और भरना, यह पोर्ट्रेट या लैंडस्केप मोड में आईपैड पर एसडीके 4.3 के लिए बॉक्स से बाहर काम करेगा:

@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
  if (self.isFirstResponder) {        
    return self;     
  }

  for (UIView *subView in self.subviews) {
    UIResponder *firstResponder = [subView findFirstResponder];
    if (firstResponder != nil) {
      return firstResponder;
    }
  }

  return nil;
}
@end

@implementation MyViewController

- (UIResponder *)currentFirstResponder {
  return [self.view findFirstResponder];
}

- (IBAction)editingEnded:sender {
  [sender resignFirstResponder];
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
  [textField resignFirstResponder];
  return NO;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
  UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
  [_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillShow:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {
    NSDictionary* userInfo = [notification userInfo];

    // we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
    NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
    if (!keyboardFrameValue) {
      keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
    }

    // Reduce the tableView height by the part of the keyboard that actually covers the tableView
    CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
    CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
    CGRect frame = _tableView.frame;
    if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
      windowRect = CGRectMake(windowRect.origin.y, windowRect.origin.x, windowRect.size.height, windowRect.size.width);
      viewRectAbsolute = CGRectMake(viewRectAbsolute.origin.y, viewRectAbsolute.origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
    }
    frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = frame;
    [UIView commitAnimations];

    UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
    NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];

    // iOS 3 sends hide and show notifications right after each other
    // when switching between textFields, so cancel -scrollToOldPosition requests
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    _topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
    [_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
  }
}

- (void) scrollToOldPosition {
  [_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
  if ([self currentFirstResponder] != nil) {

    NSDictionary* userInfo = [notification userInfo];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    _tableView.frame = self.view.bounds;
    [UIView commitAnimations];

    [self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
  }
}   

@end

I have just solved such a problem by myself after I referred a mass of solutions found via Google and .

सबसे पहले, कृपया आश्वस्त करें कि आपने अपने UIScrollView का आईबीओलेट स्थापित किया है, फिर कृपया http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html पर नज़र डालें । अंत में, यदि आप पृष्ठभूमि को स्क्रॉल कर सकते हैं, लेकिन कीबोर्ड अभी भी टेक्स्ट फ़ील्ड्स को कवर करता है, तो कृपया कोड के इस टुकड़े को देखें:

// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;

if (aRect.size.height < activeField.frame.origin.y+activeField.frame.size.height) {

    CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y+activeField.frame.size.height-aRect.size.height);

    [scrollView setContentOffset:scrollPoint animated:YES];

इस टुकड़े और ऐप्पल के बीच मुख्य अंतर अगर स्थिति में है। मेरा मानना ​​है कि सेब की स्क्रॉल दूरी की गणना और कुंजीपटल द्वारा कवर किए गए टेक्स्ट फ़ील्ड की स्थिति सटीक नहीं है, इसलिए मैंने उपरोक्त के रूप में अपना संशोधन किया है।

अगर यह काम करता है तो मुझे बताएं


मुझे एक ही समस्या थी लेकिन ध्यान दिया कि यह केवल एक दृश्य में दिखाई देता है। तो मैंने नियंत्रकों में मतभेदों की तलाश शुरू कर दी।

मुझे पता चला कि स्क्रॉलिंग व्यवहार में सेट किया गया है - (void)viewWillAppear:(BOOL)animated सुपर इंस्टेंस के - (void)viewWillAppear:(BOOL)animated

तो इस तरह कार्यान्वित करना सुनिश्चित करें:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // your code
}

और इससे कोई फर्क नहीं पड़ता कि आप UIViewController या UITableViewController उपयोग करते हैं; UIViewController में self.view के सबव्यूव के रूप में UITableView डालने के द्वारा इसे चेक किया गया। यह वही व्यवहार था। कॉल [super viewWillAppear:animated]; कॉल को स्क्रॉल करने की अनुमति नहीं दी गई थी [super viewWillAppear:animated]; याद आ रही थी।


I ran into something like your problem (I wanted a screen similar to the iPhone's settings.app with a bunch of editable cells stacked on on top of another) and found that this approach worked well:

sliding uitextfields around to avoid


My approach:

I first subclass UITextField and add an indexPath property. In the cellFor... Method i hand over the indexPath property.

Then I add following code:

UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:textField.indexPath];

CGPoint cellPoint = [cell convertPoint:textField.center toView:self.tableView];
[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, cellPoint.y-50);}];

to the textFieldShould/WillBegin...etc.

When the Keyboard disappears you have to reverse it with:

[UIView animateWithDuration:0.3 animations:^(void){self.tableView.contentOffset = CGPointMake(0, 0);}];

If you use a uitableview to place your textfields ( from Jeff Lamarche ), you can just scroll the tableview using the delegate method like so.

(Note: my text fields are stored in an array with the same index as there row in the tableview)

- (void) textFieldDidBeginEditing:(UITextField *)textField
    {

        int index;
        for(UITextField *aField in textFields){

            if (textField == aField){
                index = [textFields indexOfObject:aField]-1;
            }
        }

         if(index >= 0) 
            [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];

        [super textFieldDidBeginEditing:textField];
    }

किसी भी उत्तर ने मेरी मदद नहीं की (मेरे पास सभी लक्ष्यों से जुड़े मेरे फोड थे, कॉन्फ़िगरेशन सेटअप को सही तरीके से सेट करते थे, कोर्रेक्टी सेट सर्च पथ "$ (विरासत)" आदि ...)।

मानक इंस्टॉल / अपडेट कमांड का उपयोग कर नवीनतम, डीबग संस्करण में कोकोपोड अपडेट किए जाने के बाद समस्या स्वयं गायब हो गई:

   gem install cocoapods --pre

या:

   sudo gem install cocoapods --pre

(अगर स्थापना के दौरान सूडो का इस्तेमाल किया गया था)।

यह कोकोपोड्स बग होना चाहिए।





ios iphone uitableview keyboard scroll