ios - كيفية جعل إيتكستفيلد تتحرك صعودا عندما لوحة المفاتيح موجودة؟


مع إفون سك:

لدي UITextFields مع UITextFields أن إحضار لوحة المفاتيح. أنا بحاجة إليها لتكون قادرة على:

  1. السماح التمرير من محتويات UIScrollView لرؤية حقول النص الأخرى مرة واحدة يتم إحضار لوحة المفاتيح حتى

  2. تلقائيا "القفز" (عن طريق التمرير لأعلى) أو تقصير

وأنا أعلم أنني بحاجة إلى UIScrollView . لقد حاولت تغيير فئة بلدي UIView إلى UIScrollView ولكن ما زلت غير قادر على تمرير مربعات النص لأعلى أو لأسفل.

هل أنا بحاجة إلى كل من إيفيو و UIScrollView ؟ هل يذهب المرء داخل الآخر؟ [إديت: أنا أعلم الآن أنك تريد UIView داخل UIScrollView ، والحيلة هي لضبط حجم المحتوى من UIScrollView إلى حجم الإطار من UIView .]

ثم ما الذي يجب تنفيذه من أجل التمرير تلقائيا إلى حقل النص النشط؟

من الناحية المثالية كما أن الكثير من الإعداد للمكونات ممكن سيتم في واجهة منشئ. أود فقط كتابة التعليمات البرمجية لما يحتاج إليها.

ملاحظة: UIView (أو UIScrollView ) التي أعمل معها هو رفعت من قبل تاببار ( UITabBar )، الذي يحتاج إلى أن تعمل كالمعتاد.

تحرير: أنا إضافة شريط التمرير فقط عندما تأتي لوحة المفاتيح حتى. على الرغم من انها ليست هناك حاجة، وأنا أشعر أنه يوفر واجهة أفضل لأنه ثم يمكن للمستخدم التمرير وتغيير صناديق النص، على سبيل المثال.

لقد حصلت على العمل حيث يمكنني تغيير حجم الإطار من UIScrollView عندما لوحة المفاتيح يذهب صعودا وهبوطا. أنا ببساطة باستخدام:

-(void)textFieldDidBeginEditing:(UITextField *)textField { 
    //Keyboard becomes visible
    scrollView.frame = CGRectMake(scrollView.frame.origin.x, 
                     scrollView.frame.origin.y, 
scrollView.frame.size.width,
scrollView.frame.size.height - 215 + 50);   //resize
}

-(void)textFieldDidEndEditing:(UITextField *)textField {
   //keyboard will hide
    scrollView.frame = CGRectMake(scrollView.frame.origin.x, 
       scrollView.frame.origin.y, 
     scrollView.frame.size.width,
      scrollView.frame.size.height + 215 - 50); //resize
}

ولكن هذا لا تلقائيا "تتحرك صعودا" أو مركز حقول النص السفلي في المنطقة المرئية، وهو ما أود حقا.



Answers



  1. سوف تحتاج فقط سكرولفيو إذا كانت محتويات لديك الآن لا يصلح في شاشة اي فون. (إذا كنت تقوم بإضافة سكرولفيو على أنها سوبيرفيو للمكونات فقط لجعل تكستفيلد التمرير حتى عندما لوحة المفاتيح يأتي، ثم انها ليست هناك حاجة).

  2. لعرض حقول النص دون أن تكون مخفية من قبل لوحة المفاتيح، والطريقة القياسية هي لنقل أعلى / أسفل عرض وجود تكستفيلدس كلما يتم عرض لوحة المفاتيح.

إليك بعض نماذج الشفرة:

#define kOFFSET_FOR_KEYBOARD 80.0

-(void)keyboardWillShow {
    // Animate the current view out of the way
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)keyboardWillHide {
    if (self.view.frame.origin.y >= 0)
    {
        [self setViewMovedUp:YES];
    }
    else if (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:mailTf])
    {
        //move the main view, so that the keyboard does not hide it.
        if  (self.view.frame.origin.y >= 0)
        {
            [self setViewMovedUp:YES];
        }
    }
}

//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3]; // if you want to slide up the view

    CGRect rect = self.view.frame;
    if (movedUp)
    {
        // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
        // 2. increase the size of the view so that the area behind the keyboard is covered up.
        rect.origin.y -= kOFFSET_FOR_KEYBOARD;
        rect.size.height += kOFFSET_FOR_KEYBOARD;
    }
    else
    {
        // revert back to the normal state.
        rect.origin.y += kOFFSET_FOR_KEYBOARD;
        rect.size.height -= kOFFSET_FOR_KEYBOARD;
    }
    self.view.frame = rect;

    [UIView commitAnimations];
}


- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // register for keyboard notifications
    [[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
{
    [super viewWillDisappear:animated];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}



كنت أيضا وجود الكثير من المسألة مع UITextFields يؤلف من UITextFields متعددة، منها، واحد أو أكثر من ذلك سوف تحصل على حجب من قبل لوحة المفاتيح عندما يتم تحريرها.

وفيما يلي بعض الأشياء التي يجب مراعاتها إذا لم يكن لديك UIScrollView التمرير بشكل صحيح.

1) تأكد من أن كونتنتسيزي الخاص بك أكبر من حجم الإطار UIScrollView . طريقة لفهم UIScrollViews هو أن UIScrollView مثل نافذة عرض على المحتوى المحدد في كونتنتسيزي. حتى عندما من أجل UIScrollview للتمرير في أي مكان، يجب كونتنتسيزي أكبر من UIScrollView . عدا ذلك، لا يوجد التمرير المطلوب كما كل شيء معرف في كونتنتزيزي مرئيا بالفعل. راجع للشغل، CGSizeZero الافتراضي = CGSizeZero .

2) الآن بعد أن فهمت أن UIScrollView هو حقا نافذة على "المحتوى" الخاص بك، والطريقة للتأكد من أن لوحة المفاتيح لا تحجب عرض UIScrollView's الخاص بك "نافذة" سيكون لتغيير حجم UIScrollView بحيث عندما لوحة المفاتيح موجودة، كنت لديها نافذة إيسكرولفيو الحجم فقط الأصلي إيسكرولفيو frame.size.height ناقص ارتفاع لوحة المفاتيح. سيضمن ذلك أن نافذتك هي منطقة صغيرة قابلة للعرض فقط.

3) وهنا الصيد: عندما نفذت لأول مرة هذا أنا أحسب وأود أن الحصول على CGRect من CGRect تحريرها ودعوة طريقة سكرولريكتوفيسيبل إيسكرولفيو UIScrollView's . نفذت الأسلوب UITextFieldDelegate مع استدعاء الأسلوب scrollRecToVisible . هذا العمل في الواقع مع تأثير جانبي غريب أن التمرير سوف المفاجئة UITextField في الموقف. لأطول وقت لم أستطع معرفة ما كان عليه. ثم علقت على textFieldDidBeginEditing المندوب الأسلوب وجميع العمل !! (؟؟؟). كما اتضح، وأعتقد أن UIScrollView فعلا ضمنا يجلب UITextField تحريرها حاليا في نافذة للعرض ضمنيا. كان بلدي تنفيذ الأسلوب UITextFieldDelegate والدعوة اللاحقة إلى scrollRecToVisible زائدة عن الحاجة وكان السبب في تأثير جانبي غريب.

حتى هنا هي خطوات للتمرير بشكل صحيح UITextField الخاص بك في UITextField في المكان عندما تظهر لوحة المفاتيح.

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad 
{
    [super viewDidLoad];

    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:self.view.window];
    // register for keyboard notifications
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification 
                                               object:self.view.window];
    keyboardIsShown = NO;
    //make contentSize bigger than your scrollSize (you will need to figure out for your own use case)
    CGSize scrollContentSize = CGSizeMake(320, 345);
    self.scrollView.contentSize = scrollContentSize;
}

- (void)keyboardWillHide:(NSNotification *)n
{
    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;


    // resize the scrollview
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height += (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];

    keyboardIsShown = NO;
}

- (void)keyboardWillShow:(NSNotification *)n
{
    // This is an ivar I'm using to ensure that we do not do the frame size adjustment on the `UIScrollView` if the keyboard is already shown.  This can happen if the user, after fixing editing a `UITextField`, scrolls the resized `UIScrollView` to another `UITextField` and attempts to edit the next `UITextField`.  If we were to resize the `UIScrollView` again, it would be disastrous.  NOTE: The keyboard notification will fire even when the keyboard is already shown.
    if (keyboardIsShown) {
        return;
    }

    NSDictionary* userInfo = [n userInfo];

    // get the size of the keyboard
    CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;

    // resize the noteView
    CGRect viewFrame = self.scrollView.frame;
    // I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
    viewFrame.size.height -= (keyboardSize.height - kTabBarHeight);

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationBeginsFromCurrentState:YES];
    [self.scrollView setFrame:viewFrame];
    [UIView commitAnimations];
    keyboardIsShown = YES;
}
  1. سجل للإشعارات لوحة المفاتيح في viewDidLoad
  2. إلغاء تسجيل نوفيتيكاتيونس لوحة المفاتيح في viewDidUnload
  3. تأكد من تعيين viewDidLoad في viewDidLoad
  4. تقليص UIScrollView عند وجود لوحة المفاتيح
  5. العودة إلى الوراء UIScrollView عندما يذهب لوحة المفاتيح بعيدا.
  6. استخدام إيفار للكشف عن إذا لوحة المفاتيح هو مبين بالفعل على الشاشة منذ يتم إرسال إشعارات لوحة المفاتيح في كل مرة يتم كلف UITextField حتى لو لوحة المفاتيح موجودة بالفعل لتجنب تقلص UIScrollView عندما يكون بالفعل تقلصت

شيء واحد أن نلاحظ هو أن UIKeyboardWillShowNotification سوف يطلق النار حتى عندما لوحة المفاتيح هو بالفعل على الشاشة عند التبويب على UITextField آخر. أخذت الرعاية من هذا باستخدام إيفار لتجنب تغيير حجم إيسكرولفيو عندما لوحة المفاتيح هو بالفعل على الشاشة. تغيير حجم عن غير قصد UIScrollView عندما لوحة المفاتيح هو بالفعل سيكون هناك كارثية!

نأمل أن يحفظ هذا الرمز بعض منكم الكثير من الصداع.




انها في الواقع أفضل فقط لاستخدام تنفيذ أبل، على النحو المنصوص عليه في المستندات . ومع ذلك، فإن التعليمات البرمجية التي تقدمها خلل. استبدال الجزء الموجود في لوحة المفاتيحالآلة: أسفل التعليقات إلى ما يلي:

NSDictionary* info = [aNotification userInfo];
CGRect keyPadFrame=[[UIApplication sharedApplication].keyWindow convertRect:[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue] fromView:self.view];
CGSize kbSize =keyPadFrame.size;
CGRect activeRect=[self.view convertRect:activeField.frame fromView:activeField.superview];
CGRect aRect = self.view.bounds;
aRect.size.height -= (kbSize.height);

CGPoint origin =  activeRect.origin;
origin.y -= backScrollView.contentOffset.y;
if (!CGRectContainsPoint(aRect, origin)) {
    CGPoint scrollPoint = CGPointMake(0.0,CGRectGetMaxY(activeRect)-(aRect.size.height));
    [backScrollView setContentOffset:scrollPoint animated:YES];
}

المشاكل مع رمز أبل هي هذه: (1) أنها دائما حساب إذا كانت النقطة ضمن إطار الرأي، لكنه سكرولفيو، لذلك قد يكون بالفعل تمرير وتحتاج إلى حساب لهذا الإزاحة:

origin.y -= scrollView.contentOffset.y

(2) أنها تحول كونتنتوفست من ارتفاع لوحة المفاتيح، ولكننا نريد العكس (نريد لتحويل كونتنتوفست من الارتفاع الذي هو مرئي على الشاشة، وليس ما هو ليس):

activeField.frame.origin.y-(aRect.size.height)



في [self animateTextField:textField up:YES] استدعاء الدالة [self animateTextField:textField up:YES] مثل ذلك:

-(void)textFieldDidBeginEditing:(UITextField *)textField 
{ 
    [self animateTextField:textField up:YES]; 
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField:textField up:NO];
}

-(void)animateTextField:(UITextField*)textField up:(BOOL)up
{
    const int movementDistance = -130; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? movementDistance : -movementDistance); 

    [UIView beginAnimations: @"animateTextField" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}

آمل أن يساعدك هذا الرمز.

في سويفت 2

func animateTextField(textField: UITextField, up: Bool) 
{
     let movementDistance:CGFloat = -130
     let movementDuration: Double = 0.3

     var movement:CGFloat = 0
     if up 
     {
         movement = movementDistance
     }
     else 
     {
         movement = -movementDistance
     }
     UIView.beginAnimations("animateTextField", context: nil)
     UIView.setAnimationBeginsFromCurrentState(true)
     UIView.setAnimationDuration(movementDuration)
     self.view.frame = CGRectOffset(self.view.frame, 0, movement)
     UIView.commitAnimations()
}


func textFieldDidBeginEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:true)
}

func textFieldDidEndEditing(textField: UITextField) 
{
    self.animateTextField(textField, up:false)
}

سويفت 3

 func animateTextField(textField: UITextField, up: Bool)
    {
        let movementDistance:CGFloat = -130
        let movementDuration: Double = 0.3

        var movement:CGFloat = 0
        if up
        {
            movement = movementDistance
        }
        else
        {
            movement = -movementDistance
        }
        UIView.beginAnimations("animateTextField", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration)
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }


    func textFieldDidBeginEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:true)
    }

    func textFieldDidEndEditing(textField: UITextField)
    {
        self.animateTextField(textField: textField, up:false)
    }



فقط باستخدام تكستفيلدس:

1a) باستخدام Interface Builder : حدد جميع تكستفيلدس => تحرير => تضمين في => سكرولفيو

1b) تضمين يدويا تكستفيلدز في إيسكرولفيو دعا سكرولفيو

2) تعيين UITextFieldDelegate

3) تعيين كل textField.delegate = self; (أو إجراء اتصالات في Interface Builder )

4) نسخ / لصق:

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    CGPoint scrollPoint = CGPointMake(0, textField.frame.origin.y);
    [scrollView setContentOffset:scrollPoint animated:YES];
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    [scrollView setContentOffset:CGPointZero animated:YES];
}



لقد وضعت معا، قطرة في UICollectionView ، UICollectionView وحتى الفئة الفرعية UICollectionView أن يعتني نقل جميع الحقول النصية داخله للخروج من لوحة المفاتيح.

عندما تكون لوحة المفاتيح على وشك الظهور، سوف تجد الفئة الفرعية سوبفيو التي سيتم تعديلها، وضبط إطارها وإزاحة المحتوى للتأكد من أن هذا العرض مرئي، مع الرسوم المتحركة لتتناسب مع لوحة المفاتيح المنبثقة. عندما تختفي لوحة المفاتيح، فإنه يستعيد حجمه السابق.

يجب أن تعمل مع أي إعداد أساسا، إما واجهة القائم على UITableView ، أو واحدة تتكون من وجهات النظر وضعت يدويا.

هنا 'تيس: حل لنقل حقول النص من الطريق من لوحة المفاتيح




للحل الشامل ، وهنا كان نهجي لتنفيذ إكيبواردماناجر .

STEP1: - لقد UITextField الإخطارات العالمية من UITextField ، UITextView ، و UIKeyboard في فئة سينغلتون. أسميها إكيبواردماناجر .

UIKeyboardWillShowNotification : - إذا وجدت UIKeyboardWillShowNotification ، UITextFieldTextDidBeginEditingNotification أو الإخطارات UITextViewTextDidBeginEditingNotification ، أحاول الحصول على topMostViewController مثيل من التسلسل الهرمي UIWindow.rootViewController . من أجل الكشف بشكل صحيح UITextField / UITextView على ذلك، يحتاج إطار topMostViewController.view .

STEP3: - أنا حساب المسافة المتوقعة المتوقعة من topMostViewController.view فيما يتعلق أول رد UITextField / UITextView .

Step4: - انتقلت topMostViewController.view.frame أعلى / أسفل وفقا لمسافة الخطوة المتوقعة.

Step5: - إذا وجدت UIKeyboardWillHideNotification ، UITextFieldTextDidEndEditingNotification أو إعلام UITextViewTextDidEndEditingNotification ، مرة أخرى في محاولة للحصول على topMostViewController من التسلسل الهرمي UIWindow.rootViewController .

Step6: - أنا حساب المسافة بالانزعاج من topMostViewController.view الذي يحتاج إلى استعادة إلى انها الموقف الأصلي.

Step7: - أنا استعادة topMostViewController.view.frame أسفل وفقا للمسافة المضطربة.

Step8: - أنا مثيل سينغليتون إكيبواردماناجر الدرجة المثيل على تحميل التطبيق، لذلك كل UITextField / UITextView في التطبيق سوف ضبط تلقائيا وفقا لمسافة الخطوة المتوقعة.

هذا كل إكيبواردماناجر تفعل لك مع أي خط من الكود حقا !! تحتاج فقط إلى سحب وإسقاط ملف المصدر ذات الصلة إلى المشروع. إكيبواردماناجر أيضا دعم اتجاه الجهاز ، التلقائي إيتولبار إدارة ، كيبكيبواردديستانسفرومتكستفيلد وأكثر بكثير مما كنت اعتقد.




للمبرمجين سويفت :

وهذا سوف تفعل كل شيء بالنسبة لك، وضعت للتو هذه في فئة تحكم عرض وتنفيذ UITextFieldDelegate إلى وحدة تحكم الرأي الخاص بك وتعيين مندوب UITextFieldDelegate إلى self

textField.delegate = self // Setting delegate of your UITextField to self

تنفيذ أساليب رد المندوب:

func textFieldDidBeginEditing(textField: UITextField) {
    animateViewMoving(true, moveValue: 100)
}

func textFieldDidEndEditing(textField: UITextField) {
    animateViewMoving(false, moveValue: 100)
}

// Lifting the view up
func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}



هناك بالفعل الكثير من الأجوبة، ولكن لا يزال أيا من الحلول أعلاه كان كل الاشياء يتوهم المواقع المطلوبة ل "الكمال" خالية من الأخطاء خالية من الوراء، متوافق مع الرسوم المتحركة وميض خالية من الرسوم المتحركة. (علة عندما الرسوم المتحركة الإطار / الحدود و كونتنتوفسيت معا، والتوجهات واجهة مختلفة، باد لوحة المفاتيح الانقسام، ...)
واسمحوا لي أن أشاطرني الحل:
(على افتراض أن قمت بإعداد UIKeyboardWill(Show|Hide)Notification )

// Called when UIKeyboardWillShowNotification is sent
- (void)keyboardWillShow:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = [notification userInfo];

    CGRect keyboardFrameInWindow;
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindow];

    // the keyboard frame is specified in window-level coordinates. this calculates the frame as if it were a subview of our view, making it a sibling of the scroll view
    CGRect keyboardFrameInView = [self.view convertRect:keyboardFrameInWindow fromView:nil];

    CGRect scrollViewKeyboardIntersection = CGRectIntersection(_scrollView.frame, keyboardFrameInView);
    UIEdgeInsets newContentInsets = UIEdgeInsetsMake(0, 0, scrollViewKeyboardIntersection.size.height, 0);

    // this is an old animation method, but the only one that retains compaitiblity between parameters (duration, curve) and the values contained in the userInfo-Dictionary.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    _scrollView.contentInset = newContentInsets;
    _scrollView.scrollIndicatorInsets = newContentInsets;

    /*
     * Depending on visual layout, _focusedControl should either be the input field (UITextField,..) or another element
     * that should be visible, e.g. a purchase button below an amount text field
     * it makes sense to set _focusedControl in delegates like -textFieldShouldBeginEditing: if you have multiple input fields
     */
    if (_focusedControl) {
        CGRect controlFrameInScrollView = [_scrollView convertRect:_focusedControl.bounds fromView:_focusedControl]; // if the control is a deep in the hierarchy below the scroll view, this will calculate the frame as if it were a direct subview
        controlFrameInScrollView = CGRectInset(controlFrameInScrollView, 0, -10); // replace 10 with any nice visual offset between control and keyboard or control and top of the scroll view.

        CGFloat controlVisualOffsetToTopOfScrollview = controlFrameInScrollView.origin.y - _scrollView.contentOffset.y;
        CGFloat controlVisualBottom = controlVisualOffsetToTopOfScrollview + controlFrameInScrollView.size.height;

        // this is the visible part of the scroll view that is not hidden by the keyboard
        CGFloat scrollViewVisibleHeight = _scrollView.frame.size.height - scrollViewKeyboardIntersection.size.height;

        if (controlVisualBottom > scrollViewVisibleHeight) { // check if the keyboard will hide the control in question
            // scroll up until the control is in place
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y += (controlVisualBottom - scrollViewVisibleHeight);

            // make sure we don't set an impossible offset caused by the "nice visual offset"
            // if a control is at the bottom of the scroll view, it will end up just above the keyboard to eliminate scrolling inconsistencies
            newContentOffset.y = MIN(newContentOffset.y, _scrollView.contentSize.height - scrollViewVisibleHeight);

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        } else if (controlFrameInScrollView.origin.y < _scrollView.contentOffset.y) {
            // if the control is not fully visible, make it so (useful if the user taps on a partially visible input field
            CGPoint newContentOffset = _scrollView.contentOffset;
            newContentOffset.y = controlFrameInScrollView.origin.y;

            [_scrollView setContentOffset:newContentOffset animated:NO]; // animated:NO because we have created our own animation context around this code
        }
    }

    [UIView commitAnimations];
}


// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillHide:(NSNotification*)notification
{
    // if we have no view or are not visible in any window, we don't care
    if (!self.isViewLoaded || !self.view.window) {
        return;
    }

    NSDictionary *userInfo = notification.userInfo;

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:[[userInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[[userInfo valueForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];

    // undo all that keyboardWillShow-magic
    // the scroll view will adjust its contentOffset apropriately
    _scrollView.contentInset = UIEdgeInsetsZero;
    _scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;

    [UIView commitAnimations];
}



أردت إضافة تعليق على إجابة شيون، ولكني على ما يبدو ليس لدي ما يكفي من نقاط المندوبين لإضافة تعليقات. ربما يمكن للشخص الذي لديه نقاط أكثر إضافة تعليق مع المعلومات أدناه، ثم سأحذف هذه الإجابة ...

وقال شيون "كما اتضح، وأعتقد أن إيسكرولفيو فعلا ضمنا يجلب إتكستفيلد تحريرها حاليا في نافذة للعرض ضمنا" يبدو أن هذا ينطبق على دائرة الرقابة الداخلية 3.1.3، ولكن ليس 3.2، 4.0، أو 4.1. كان علي إضافة سكرولريكتوفيسيبل صريحة من أجل جعل إيتكستفيلد مرئية على دائرة الرقابة الداخلية> = 3.2.




توضح هذه الوثيقة حلا لهذه المشكلة. نظرة على التعليمات البرمجية المصدر تحت "نقل المحتوى الذي يقع تحت لوحة المفاتيح". انها واضحة جدا.

إديت: لاحظت وجود خلل في المثال. ربما كنت ترغب في الاستماع ل UIKeyboardWillHideNotification بدلا من UIKeyboardDidHideNotification . وإلا سيتم قص وجهة نظر التمرير خلف لوحة المفاتيح لمدة الرسوم المتحركة إغلاق لوحة المفاتيح.




شيء واحد هو أن تنظر في ما إذا كنت تريد من أي وقت مضى لاستخدام UITextField من تلقاء نفسها. أنا لم يأت عبر أي تطبيقات اي فون مصممة تصميما جيدا التي تستخدم في الواقع UITextFields خارج UITextFields .

وسوف يكون هناك بعض العمل الإضافي، ولكن أوصي لك تنفيذ جميع وجهات النظر إدخال البيانات وجهة نظر الجدول. إضافة UITextView إلى UITextView الخاص بك.




الحل الأسهل وجدت

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self animateTextField: textField up: YES];
}


- (void)textFieldDidEndEditing:(UITextField *)textField
{
    [self animateTextField: textField up: NO];
}

- (void) animateTextField: (UITextField*) textField up: (BOOL) up
{
    const int movementDistance = 80; // tweak as needed
    const float movementDuration = 0.3f; // tweak as needed

    int movement = (up ? -movementDistance : movementDistance);

    [UIView beginAnimations: @"anim" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];
}



الإصلاح يذكر أن يعمل لكثير UITextFields

#pragma mark UIKeyboard handling

#define kMin 150

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
   if (currTextField) {
      [currTextField release];
   }
   currTextField = [sender retain];
   //move the main view, so that the keyboard does not hide it.
   if (self.view.frame.origin.y + currTextField.frame.origin. y >= kMin) {
        [self setViewMovedUp:YES]; 
   }
}



//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
   [UIView beginAnimations:nil context:NULL];
   [UIView setAnimationDuration:0.3]; // if you want to slide up the view

   CGRect rect = self.view.frame;
   if (movedUp)
   {
      // 1. move the view's origin up so that the text field that will be hidden come above the keyboard 
      // 2. increase the size of the view so that the area behind the keyboard is covered up.
      rect.origin.y = kMin - currTextField.frame.origin.y ;
   }
   else
   {
      // revert back to the normal state.
      rect.origin.y = 0;
   }
   self.view.frame = rect;

   [UIView commitAnimations];
}


- (void)keyboardWillShow:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately

   if ([currTextField isFirstResponder] && currTextField.frame.origin.y + self.view.frame.origin.y >= kMin)
   {
      [self setViewMovedUp:YES];
   }
   else if (![currTextField isFirstResponder] && currTextField.frame.origin.y  + self.view.frame.origin.y < kMin)
   {
      [self setViewMovedUp:NO];
   }
}

- (void)keyboardWillHide:(NSNotification *)notif
{
   //keyboard will be shown now. depending for which textfield is active, move up or move down the view appropriately
   if (self.view.frame.origin.y < 0 ) {
      [self setViewMovedUp:NO];
   }

}


- (void)viewWillAppear:(BOOL)animated
{
   // register for keyboard notifications
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) 
                                                name:UIKeyboardWillShowNotification object:self.view.window]; 
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) 
                                                name:UIKeyboardWillHideNotification object:self.view.window]; 
}

- (void)viewWillDisappear:(BOOL)animated
{
   // unregister for keyboard notifications while not visible.
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
}



كود RPDP ويتحرك بنجاح حقل النص للخروج من الطريق من لوحة المفاتيح. ولكن عندما انتقل إلى الأعلى بعد استخدام وفصل لوحة المفاتيح، تم تمريره في أعلى حتى من وجهة النظر. وهذا ينطبق على محاكي والجهاز. لقراءة محتوى في الجزء العلوي من هذا الرأي، على المرء أن إعادة العرض.

لا البرمجية التالية له من المفترض أن يحضر الرأي التراجع؟

else
{
    // revert back to the normal state.
    rect.origin.y += kOFFSET_FOR_KEYBOARD;
    rect.size.height -= kOFFSET_FOR_KEYBOARD;
}



أنا لست متأكدا مما اذا كان تحريك الرأي حتى هو النهج الصحيح، وفعلت ذلك بطريقة differente، تغيير حجم UIScrollView. شرحت في التفاصيل على القليل من المادة




ان يعود الى حالة العرض الأصلي، إضافة:

-(void)textFieldDidEndEditing:(UITextField *)sender

{
    //move the main view, so that the keyboard does not hide it.
    if  (self.view.frame.origin.y < 0)
    {
        [self setViewMovedUp:NO];
    }
}



هناك الكثير من الحلول، ولكني قضاء بضع ساعات قبل أن تبدأ أعمال. لذلك، أنا وضعت هذا الرمز هنا (فقط لصق لهذا المشروع، أي تعديلات لا تحتاج):

@interface RegistrationViewController : UIViewController <UITextFieldDelegate>{
    UITextField* activeField;
    UIScrollView *scrollView;
}
@end

- (void)viewDidLoad
{
    [super viewDidLoad];

    scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];

    //scrool view must be under main view - swap it
    UIView* natView = self.view;
    [self setView:scrollView];
    [self.view addSubview:natView];

    CGSize scrollViewContentSize = self.view.frame.size;
    [scrollView setContentSize:scrollViewContentSize];

    [self registerForKeyboardNotifications];
}

- (void)viewDidUnload {
    activeField = nil;
    scrollView = nil;
    [self unregisterForKeyboardNotifications];
    [super viewDidUnload];
}

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShown:)
                                                 name:UIKeyboardWillShowNotification object:nil];

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

}

-(void)unregisterForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];
    // unregister for keyboard notifications while not visible.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

- (void)keyboardWillShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect frame = self.view.frame;
    frame.size.height -= kbSize.height;
    CGPoint fOrigin = activeField.frame.origin;
    fOrigin.y -= scrollView.contentOffset.y;
    fOrigin.y += activeField.frame.size.height;
    if (!CGRectContainsPoint(frame, fOrigin) ) {
        CGPoint scrollPoint = CGPointMake(0.0, activeField.frame.origin.y + activeField.frame.size.height - frame.size.height);
        [scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
     [scrollView setContentOffset:CGPointZero animated:YES];
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    activeField = textField;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    activeField = nil;
}

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

PS: آمل رمز مساعدة شخص ما جعل النتيجة المرجوة بسرعة. (كسكودي 4.5)




محاولة هذه الخدعة قصيرة ...

 - (void)textFieldDidBeginEditing:(UITextField *)textField
    {
        [self animateTextField: textField up: YES];
    }

    - (void)textFieldDidEndEditing:(UITextField *)textField
    {
        [self animateTextField: textField up: NO];
    }

    - (void) animateTextField: (UITextField*) textField up: (BOOL) up
    {
        const int movementDistance = textField.frame.origin.y / 2; // tweak as needed
        const float movementDuration = 0.3f; // tweak as needed

        int movement = (up ? -movementDistance : movementDistance);

        [UIView beginAnimations: @"anim" context: nil];
        [UIView setAnimationBeginsFromCurrentState: YES];
        [UIView setAnimationDuration: movementDuration];
        self.view.frame = CGRectOffset(self.view.frame, 0, movement);
        [UIView commitAnimations];
    }

سعيد الترميز:) ....




@ user271753

للحصول على وجهة نظركم إلى إضافة الأصلي:

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



أنها لا تتطلب وجهة نظر التمرير لتكون قادرة على تحريك إطار الرأي. يمكنك تغيير إطار من viewcontroller'sالعرض بحيث يتحرك عرض كامل حتى ما يكفي لوضع حقل النص firstresponder فوق لوحة المفاتيح. عندما واجهت هذه المشكلة أنا خلقت فئة فرعية من UIViewControllerأن يفعل هذا. وتلاحظ لوحة المفاتيح سوف تظهر الإخطار ويجد أول subview المستجيب و (إذا لزم الأمر) فإنه ينعش شاشة العرض الرئيسية التصاعدي فقط بما فيه الكفاية بحيث المستجيب الأول هو فوق لوحة المفاتيح. عندما يخفي لوحة المفاتيح، فإنه ينعش وجهة النظر الى حيث كان.

لاستخدام هذه الفئة الفرعية يصبح لديك تحكم عرض مخصصة فئة فرعية من GMKeyboardVC ويرث هذه الميزة (فقط تأكد إذا قمت بتطبيق viewWillAppearو viewWillDisappearأنهم يجب استدعاء السوبر). الطبقة هي على جيثب .




هنا هو الحل الإختراق خطرت لي لتخطيط معين. هذا الحل يشبه حل مات غالاغر في ذلك هو تمرير جزء في طريقة العرض. أنا لا تزال جديدة في التنمية فون، ولست على دراية كيفية عمل التصاميم. وهكذا، وهذا الإختراق.

تنفيذ بلدي بحاجة لدعم التمرير عند النقر في الميدان، وكذلك التمرير عندما يختار المستخدم التالي على لوحة المفاتيح.

كان لي UIView مع ارتفاع 775. وتنتشر الرقابة من الأساس في مجموعات من 3 على مساحة كبيرة. انتهى بي الأمر مع تخطيط IB التالية.

UIView -> UIScrollView -> [UI Components]

هنا يأتي الإختراق

I تعيين ارتفاع UIScrollView إلى 500 وحدة أكبر ثم التخطيط الفعلي (1250). ثم خلق مجموعة مع المواقف المطلقة ولست بحاجة للانتقال إلى وظيفة بسيطة للحصول عليها على أساس عدد العلامات IB.

static NSInteger stepRange[] = {
    0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 140, 140, 140, 140, 410
};

NSInteger getScrollPos(NSInteger i) {
    if (i < TXT_FIELD_INDEX_MIN || i > TXT_FIELD_INDEX_MAX) {
        return 0 ;
    return stepRange[i] ;
}

الآن كل ما عليك القيام به هو استخدام السطرين التاليين من التعليمات البرمجية في textFieldDidBeginEditing وtextFieldShouldReturn (في الحالة الأخيرة إذا كنت تقوم بإنشاء الملاحة الحقل التالي)

CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
[self.scrollView setContentOffset:point animated:YES] ;

مثال.

- (void) textFieldDidBeginEditing:(UITextField *)textField
{
    CGPoint point = CGPointMake(0, getScrollPos(textField.tag)) ;
    [self.scrollView setContentOffset:point animated:YES] ;
}


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

    NSInteger nextTag = textField.tag + 1;
    UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];

    if (nextResponder) {
        [nextResponder becomeFirstResponder];
        CGPoint point = CGPointMake(0, getScrollPos(nextTag)) ;
        [self.scrollView setContentOffset:point animated:YES] ;
    }
    else{
        [textField resignFirstResponder];
    }

    return YES ;
}

هذا الأسلوب لا "انتقل إلى الوراء" كما تفعل وسائل أخرى. ولم يكن هذا الشرط. مرة أخرى هذا كان لUIView إلى حد ما "طويل القامة، وأنا لم يكن لديك أيام لمعرفة محركات تخطيط الداخلية.




وفقا للمستندات ، ودائرة الرقابة الداخلية 3.0، UITableViewControllerالطبقة تلقائيا بتغيير حجم وحالة تصحيح عرض الجدول الخاص به عندما يكون هناك في خط تحرير حقول النص. اعتقد انها ليست كافية لوضع حقل النص داخل UITableViewCellكما أن البعض أشار.

من مستندات :

وحدة تحكم عرض جدول يدعم تحرير مضمنة من عرض جدول الصفوف. إذا، على سبيل المثال، الصفوف وجزءا لا يتجزأ من حقول النص في وضع التحرير، ومخطوطات الصف يتم تحريره فوق لوحة المفاتيح الافتراضية التي يتم عرضها.




هنا وجدت أبسط الحلول للتعامل مع لوحة المفاتيح.

تحتاج إلى مجرد نسخ لصق رمز أدناه عينة وتغيير حيز النص الخاص بك أو أي رأي الذي تريد نقل ما يصل.

الخطوة 1

مجرد نسخ لصق أدناه اثنين من طريقة في وحدة التحكم الخاصة بك

- (void)registerForKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:)
                                                 name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:)
                                                 name:UIKeyboardWillHideNotification object:nil];
}

- (void)deregisterFromKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

الخطوة 2

تسجيل وإلغاء تسجيل لوحة المفاتيح الإخطارات في viewWillAppear و viewWillDisappear طرق على التوالي.

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

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

الخطوه 3

هنا يأتي الجزء الروح، مجرد استبدال حيز النص الخاص بك، وتغيير الارتفاع وكم كنت تريد نقل رأسا على عقب.

- (void)keyboardWasShown:(NSNotification *)notification
{
    NSDictionary* info = [notification userInfo];
    CGSize currentKeyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    //you need replace your textfield instance here
    CGPoint textFieldOrigin = self.tokenForPlaceField.frame.origin;
    CGFloat textFieldHeight = self.tokenForPlaceField.frame.size.height;

    CGRect visibleRect = self.view.frame;
    visibleRect.size.height -= currentKeyboardSize.height;

    if (!CGRectContainsPoint(visibleRect, textFieldOrigin))
    {
        //you can add yor desired height how much you want move keypad up, by replacing "textFieldHeight" below

        CGPoint scrollPoint = CGPointMake(0.0, textFieldOrigin.y - visibleRect.size.height  + textFieldHeight); //replace textFieldHeight to currentKeyboardSize.height, if you want to move up with more height
        [self.scrollView setContentOffset:scrollPoint animated:YES];
    }
}

- (void)keyboardWillBeHidden:(NSNotification *)notification
{
    [self.scrollView setContentOffset:CGPointZero animated:YES];
}

إشارة : حسنا، يرجى نقدر هذا الرجل ، الذي تقاسم هذه القصاصة كود جميل، حل نظيفة.

نأمل أن يكون هذا سيكون عابس شخص مفيدة هناك.




كانت تبحث عن برنامج تعليمي جيد للمبتدئين في هذا الموضوع، وجدت أفضل تعليمي هنا .

في MIScrollView.hالمثال في الجزء السفلي من البرنامج التعليمي تأكد من وضع مسافة في

@property (nonatomic, retain) id backgroundTapDelegate;

كما ترى.




استخدام هذا الطرف الثالث لا تحتاج لكتابة حتى سطر واحد

https://github.com/hackiftekhar/IQKeyboardManager

تحميل المشروع وسحب وإسقاط IQKeyboardManager في المشروع. إذا وجدت أي مشكلة يرجى قراءة المستند التمهيدي.

الرجال حقا الصداع إزالة لإدارة لوحة المفاتيح ..

شكرا لك وحظا سعيدا!




عندما UITextFieldيكون في UITableViewCellالتمرير يجب أن يكون الإعداد تلقائيا.

إذا لم يكن هو على الأرجح بسبب رمز غير صحيح / الإعداد للtableview.

على سبيل المثال عندما إعادة تحميل مائدتي طويلة مع واحد UITextFieldفي الجزء السفلي على النحو التالي،

-(void) viewWillAppear:(BOOL)animated
{
   [self.tableview reloadData];
}

ثم كانت تحجب بلدي حيز النص في الجزء السفلي من لوحة المفاتيح التي ظهرت عندما ينقر داخل حيز النص.

لإصلاح هذه اضطررت للقيام بذلك -

-(void) viewWillAppear:(BOOL)animated
{
    //add the following line to fix issue
    [super viewWillAppear:animated];
    [self.tableview reloadData];
}



جرب هذا:

-(void)textFieldDidBeginEditing:(UITextField *)sender
{
    if ([sender isEqual:self.m_Sp_Contact])
    {
        [self.m_Scroller setContentOffset:CGPointMake(0, 105)animated:YES];          
    }
}



ملاحظة : هذه الإجابة تفترض حيز النص الخاص بك في scrollView.

انا افضل للتعامل مع هذه باستخدام scrollContentInset وscrollContentOffset بدلا من العبث مع إطارات من وجهة نظري.

أولا دعونا نستمع للإخطارات لوحة المفاتيح

//call this from viewWillAppear
-(void)addKeyboardNotifications
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
}
//call this from viewWillDisappear
-(void)removeKeyboardNotifications{
    [[NSNotificationCenter default
    Center] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}

الخطوة التالية هي للحفاظ على الممتلكات التي تمثل المستجيب الأول الحالي (UITextfield / UITextVIew التي لديها حاليا لوحة المفاتيح).

نحن نستخدم أساليب مندوب لتعيين هذه الخاصية. إذا كنت تستخدم مكون آخر، وسوف تحتاج شيئا من هذا القبيل.

لاحظ أن لحيز النص وضعناها في didBeginEditing وtextView في shouldBeginEditing. وذلك لأن يحصل على استدعاء textViewDidBeginEditing بعد UIKeyboardWillShowNotification لسبب ما.

-(BOOL)textViewShouldBeginEditing:(UITextView * )textView{
    self.currentFirstResponder = textView;
    return YES;
}

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    self.currentFirstResponder = textField;
}

وأخيرا، وهنا يكمن السحر

- (void)keyboardWillShow:(NSNotification*)aNotification{
    NSDictionary* info = [aNotification userInfo];
    CGRect kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];


    /*if currentFirstResponder is overlayed by the keyboard, move it so it bottom ends where the keyboard begins*/
    if(self.currentFirstResponder){

        //keyboard origin in currentFirstResponderFrame
        CGPoint keyboardOrigin = [self.currentFirstResponder convertPoint:kbFrame.origin fromView:nil];

        float spaceBetweenFirstResponderAndKeyboard = abs(self.currentFirstResponder.frame.size.height-keyboardOrigin.y);

        //only scroll the scrollview if keyboard overlays the first responder
        if(spaceBetweenFirstResponderAndKeyboard>0){
            //if i call setContentOffset:animate:YES it behaves differently, not sure why
            [UIView animateWithDuration:0.25 animations:^{
                [self.scrollView setContentOffset:CGPointMake(0,self.scrollView.contentOffset.y+spaceBetweenFirstResponderAndKeyboard)];
            }];
        }
    }

    //set bottom inset to the keyboard height so you can still scroll the whole content

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;

}

- (void)keyboardWillHide:(NSNotification*)aNotification{
    UIEdgeInsets contentInsets = UIEdgeInsetsZero;
    _scrollView.contentInset = contentInsets;
    _scrollView.scrollIndicatorInsets = contentInsets;
}



هذا هو الحل باستخدام سويفت.

import UIKit

class ExampleViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var scrollView: UIScrollView!

    @IBOutlet var textField1: UITextField!
    @IBOutlet var textField2: UITextField!
    @IBOutlet var textField3: UITextField!
    @IBOutlet var textField4: UITextField!
    @IBOutlet var textField5: UITextField!

    var activeTextField: UITextField!

    // MARK: - View
    override func viewDidLoad() {
        super.viewDidLoad()
        self.textField1.delegate = self
        self.textField2.delegate = self
        self.textField3.delegate = self
        self.textField4.delegate = self
        self.textField5.delegate = self
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.registerForKeyboardNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.unregisterFromKeyboardNotifications()
    }

    // MARK: - Keyboard

    // Call this method somewhere in your view controller setup code.
    func registerForKeyboardNotifications() {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
        center.addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    func unregisterFromKeyboardNotifications () {
        let center:  NSNotificationCenter = NSNotificationCenter.defaultCenter()
        center.removeObserver(self, name: UIKeyboardDidShowNotification, object: nil)
        center.removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
    }

    // Called when the UIKeyboardDidShowNotification is sent.
    func keyboardWasShown (notification: NSNotification) {
        let info : NSDictionary = notification.userInfo!
        let kbSize = (info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue() as CGRect!).size

        let contentInsets: UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;

        // If active text field is hidden by keyboard, scroll it so it's visible
        // Your app might not need or want this behavior.
        var aRect = self.view.frame
        aRect.size.height -= kbSize.height;
        if (!CGRectContainsPoint(aRect, self.activeTextField.frame.origin) ) {
            self.scrollView.scrollRectToVisible(self.activeTextField.frame, animated: true)
        }
    }

    // Called when the UIKeyboardWillHideNotification is sent
    func keyboardWillBeHidden (notification: NSNotification) {
        let contentInsets = UIEdgeInsetsZero;
        scrollView.contentInset = contentInsets;
        scrollView.scrollIndicatorInsets = contentInsets;
    }

    // MARK: -  Text Field

    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }

    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }

}