키보드가있을 때 편집을 시작할 때 UITextField를 위로 올리려면 어떻게해야합니까?


1691

iOS SDK를 사용하여 :

나는이 UIViewUITextField키보드를 가지고 있음을의. 나는 그것을 할 수 있어야합니다.

  1. UIScrollView키보드를 불러 온 후 다른 텍스트 필드를 보려면 의 내용을 스크롤 할 수 있습니다.

  2. 자동으로 "점프"(위로 스크롤) 또는 단축

나는 내가 필요하다는 것을 안다 UIScrollView. 내의 클래스를 변경 해봤 UIViewA를 UIScrollView하지만, 난 여전히 위 또는 아래로 텍스트 상자를 스크롤 할 수 없어요.

a UIView와 a 가 모두 필요 UIScrollView합니까? 하나는 다른 안으로 들어가나요?

활성 텍스트 필드로 자동 스크롤하려면 무엇을 구현해야합니까?

가능한 한 많은 구성 요소 설정이 Interface Builder에서 수행됩니다. 필요한 코드 만 작성하고 싶습니다.

참고 : 내가 작업하고 있는 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
}

그러나 이것은 가시 영역의 하단 텍스트 필드를 자동으로 "위로 이동"하거나 가운데에 두지 않습니다. 이것이 내가 정말로 원하는 것입니다.


6
이것 좀 봐. 번거롭지 않습니다. TPKeyboardAvoiding
Aruna

21
Apple에서 문서화 한 것이 가장 좋은 방법이라고 생각합니다. developer.apple.com/library/ios/#documentation/StringsTextFonts/…
Maik639

58
이 코드를 사용하십시오 .appdelegate.m 파일에 한 줄만 있으면 작동합니다. github.com/hackiftekhar/IQKeyboardManager
Pradeep Mittal

9
지금까지 찾은 가장 좋은 방법은이 오픈 소스 TPKeyboard입니다.
Zaidi

2
또 다른 방법은 그러한 내용 텍스트 필드와 TableViewController에 모두 추가하고 tableview가 이것을 처리하도록하는 것입니다.
비키 디스

답변:


1036
  1. ScrollViewiPhone 화면에 맞지 않는 내용 만 있으면됩니다. ( ScrollView구성 요소의 슈퍼 뷰로를 추가하는 경우TextField 키보드가 나타날 때 스크롤 필요하지 않습니다.)

  2. 방지하는 표준 방법 TextField키보드로 키보드 은 키보드가 표시 될 때마다보기를 위 / 아래로 이동하는 것입니다.

샘플 코드는 다음과 같습니다.

#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];
}

3
_textField는 무엇입니까? _textField가 선언되지 않았다고 코드에 복사했습니다.
Cocoa Dev

"사용자가 여기에서 편집 할 때보기가 위로 올라 가야합니다"또는 기타 무언가를 말하는 데 사용하는 필드입니다. 그러나 더 많은 필드가있는 경우 해당 필드를 제거 할 수 있습니다.
패트 릭

keyBoardWillSHow 및 KeyBoardWillHide 이벤트에서-(void) setViewMovedUp : (BOOL) movedUp을 호출하는 타자가 아닙니다!
Abduliam Rehmanius 2016 년

4
기본 뷰의 회전을 지원하는 경우 특히 유용하지 않습니다.
FractalDoctor

2
이 작업을 수행하기 위해 textFieldDidBeginEditing섹션 을 주석 처리해야했습니다 .
avance

445

또한 UIScrollView여러 개의 작곡에 많은 문제가 UITextFields있었고 그 중 하나 이상이 편집 중 키보드에 의해 가려 질 수 있습니다.

UIScrollView스크롤이 제대로되지 않으면 고려해야 할 사항이 있습니다 .

1) contentSize가 UIScrollView프레임 크기 보다 큰지 확인하십시오 . 이해하는 방법은 UIScrollViews(가)이다 UIScrollViewcontentSize에 정의 된 내용에 보는 창 같다. 따라서 UIScrollview어디에서나 스크롤하려면 contentSize가.보다 커야합니다 UIScrollView. 그렇지 않으면 contentSize에 정의 된 모든 항목이 이미 표시되므로 스크롤이 필요하지 않습니다. BTW, 기본 contentSize =CGSizeZero .

2) 이제는 이것이 UIScrollView실제로 "콘텐츠"의 창 이라는 것을 이해 했으므로 키보드가 UIScrollView's보기 "창"을 가리지 않도록하는 방법은 키보드가 UIScrollView있을 때 UIScrollView창 을 갖도록 크기를 조정하는 것입니다. 크기는 원래 UIScrollView프레임 크기 와 높이에서 키보드 높이를 뺀 크기 입니다. 이렇게하면 창이 작은 가시 영역 만 확보 할 수 있습니다.

3) 캐치가 있습니다 : 처음 이것을 구현했을 때 CGRect편집 된 텍스트 필드 를 가져 와서 UIScrollView'sscrollRecToVisible 메소드를 호출 해야한다고 생각 했습니다 . UITextFieldDelegate메서드 textFieldDidBeginEditing를 호출 하여 메서드 를 구현했습니다 scrollRecToVisible. 이것은 실제로 스크롤 것이 이상한 부작용과 협력 스냅UITextField위치로. 가장 오랫동안 나는 그것이 무엇인지 알 수 없었습니다. 그런 다음 textFieldDidBeginEditingDelegate 메서드를 주석 처리하고 모두 작동합니다 !! (???). 그것이 UIScrollView실제로 암시 적으로 현재 편집 UITextField된 것을 볼 수있는 창에 암시 적으로 가져 온다고 생각합니다 . UITextFieldDelegate메소드의 구현 과 이후의 호출 scrollRecToVisible은 중복되었으며 이상한 부작용의 원인이었습니다.

그래서 여기에 제대로 스크롤하는 단계입니다 UITextFieldA의 UIScrollView장소 때 키보드가 나타납니다으로는.

// 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. 이 있는지 확인 contentSize설정하고보다 큰 UIScrollView에서viewDidLoad
  4. 축소UIScrollView키보드가있는 경우
  5. 다시 되돌리기UIScrollView 키보드가 사라질 때.
  6. 키보드 알림은이 때마다 전송되기 때문에 키보드가 이미 화면에 표시되어있는 경우 감지하는 바르를 사용하여 UITextField키보드를 피하기 위해 이미 존재하는 경우에도 탭되고 축소UIScrollView이미 때 수축을

한 가지주의해야 할 점은 UIKeyboardWillShowNotification다른 키보드를 탭하면 키보드가 이미 화면에 있어도 작동 한다는 것 UITextField입니다. UIScrollView키보드가 이미 화면에있을 때 크기 조정을 피하기 위해 ivar을 사용 하여이 문제를 해결했습니다 . UIScrollView키보드가 이미있을 때 실수로 크기를 조정하면 재앙이 생길 것입니다!

이 코드가 여러분의 많은 두통을 덜어 주길 바랍니다.


3
위대하지만 두 가지 문제 : 1. UIKeyboardBoundsUserInfoKey더 이상 사용되지 않습니다. 2. keyboardSize가 "화면 좌표"에 있으므로 프레임을 회전하거나 크기를 조정하면 viewFrame 계산이 실패합니다.
Martin Wickman

21
@Martin Wickman - 사용 CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;대신에 사용되지 않는의UIKeyboardBoundsUserInfoKey
sottenad

1
안녕, 나는 똑같이했지만 텍스트보기는 사용자가 입력을 시작할 때만 움직입니까? 예상되는 동작입니까, 아니면 뭔가 빠졌습니까?

3
[[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size이어야합니다 [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size. 그래도 훌륭한 솔루션입니다!
j7nn7k

1
귀하의 솔루션이 마음에 들지만 더 간단하게 만들 수 있다고 생각합니다. Notification Observer에 신경 쓰지 마십시오. 대신 적절한 대리자 메서드 내에서 올바른 애니메이션 루틴을 호출하십시오 .UITextView의 경우 textViewDidBeginEditing 및 textViewDidEndEditing입니다.
AlexChaffee 2013

270

docs에 제공된대로 실제로 Apple 구현을 사용하는 것이 가장 좋습니다 . 그러나 이들이 제공하는 코드에 결함이 있습니다. keyboardWasShown:주석 바로 아래 에있는 부분을 다음으로 대체하십시오 .

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];
}

Apple 코드의 문제점은 다음과 같습니다. (1) 포인트가 뷰의 프레임 내에 있는지 항상 계산하지만 포인트 ScrollView이므로 이미 스크롤되어 해당 오프셋을 고려해야합니다.

origin.y -= scrollView.contentOffset.y

(2) 그들은 키보드의 높이에 따라 contentOffset을 이동 시키지만, 반대를 원합니다 ( contentOffset화면에 보이지 않는 높이가 아닌 높이 로 이동하고 싶습니다 ).

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

1
스크롤보기가 화면을 채우지 않는 경우
aRect

2
CGPoint origin = activeField.frame.origin + activeField.frame.size.height?를 원하지 않아야합니다. 전체 텍스트 필드를 표시하고 일부 픽셀 만 표시하면 코드가 입력되지 않기 때문입니다. 질환.
htafoya

1
이 솔루션은 가로 방향으로 작동하지 않습니다. 텍스트 필드가 뷰 포트 상단으로 날아갑니다. iOS 7.1이 설치된 iPad.
Andrew

4
더 나은 iOS 8 지원 을 위해 키보드 크기 UIKeyboardFrameEndUserInfoKeyUIKeyboardFrameBeginUserInfoKey가져올 때 대신 사용자 지정 키보드 변경 및 예측 텍스트 켜기 / 끄기 전환과 같은 항목을 선택하기 때문에 대신 사용 하는 것이 좋습니다 .
Endareth

1
@ 에고 르 : 당신의 수정은 더 잘 작동합니다-그러나 마지막 줄은 역수 여야합니다 :self.scrollView.contentOffset = self.currentSVoffset;
Morten Holmgaard

244

다음 textFieldDidBeginEditting과 같이 textFieldDidEndEditing함수 를 호출하십시오 [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)
    }

1
왜 사용하지 [UIView animateWithDuration: animations:^{ }];않습니까?
Andre Cytryn

2
const int movementDistance = -130; // 필요에 따라
Hammer

7
작은 구현에서 매우 간단합니다. ScrollViews 및 모호한 자동 레이아웃 문제로 인한 문제가 없습니다.
James Perih

4
음 ... textField 매개 변수를 전혀 사용하지 않습니다. 그렇다면 왜 함수 매개 변수로 사용합니까? 또한 Swift에서도 삼항 연산자를 사용할 수 있습니다. 코드를 덜 말끔하게 만듭니다.
stk

1
보기의 배경색이 검은 색이 아닌 경우 사용자가보기를 볼 수 없도록 창의 색상을보기와 일치하도록 설정하십시오. 즉 self.window.backgroundColor = [UIColor whiteColor];
bvmobileapps

134

TextFields를 사용하는 경우 :

1a) 사용 Interface Builder : 모든 텍스트 필드 선택 => 편집 => 포함 => ScrollView

1b) UIScrollView에 scrollField라는 텍스트 필드를 수동으로 포함

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];
}

8
그러나 textField이미 표시되어 있으면 보기를 위로 이동합니다 .
TheTiger

1
다음으로 변경 CGPointMake(0, textField.frame.origin.y);해야 함CGPointMake(0, textField.frame.origin.y + scrollView.contentInset.top);
Fury

@ Egor 댓글 후에도 작동하지 않습니다. "TheTiger"와 같이 텍스트 필드가 표시된 후에도보기를 위로 이동합니다.
rak appdev

XCode 10 변경 : "모든
텍스트 필드

116

들어 범용 솔루션 , 여기에 구현하기위한 나의 접근 방식이었다 IQKeyboardManager을 .

여기에 이미지 설명을 입력하십시오

1 단계 : - 의 I 추가 글로벌 통지 UITextField, UITextViewUIKeyboard의 싱글 클래스입니다. 나는 그것을 IQKeyboardManager 라고 부른다 .

2 단계 : - 만약 발견 UIKeyboardWillShowNotification, UITextFieldTextDidBeginEditingNotification또는 UITextViewTextDidBeginEditingNotification알림, 내가 좀하려고 topMostViewController로부터 인스턴스를 UIWindow.rootViewController계층 구조. 제대로 밝히기 위해서는 UITextField/ UITextView그것에서 topMostViewController.view의 프레임을 조정해야합니다.

Step3 :-topMostViewController.view 첫 번째 반응 UITextField/에 대한 예상 이동 거리를 계산 했습니다 UITextView.

4 단계는 : - 나는 이동 topMostViewController.view.frame예상 이동 거리에 따라 UP / DOWN.

Step5 :-UIKeyboardWillHideNotification , UITextFieldTextDidEndEditingNotification또는 UITextViewTextDidEndEditingNotification알림 이 발견 되면 계층 topMostViewController에서 인스턴스를 다시 가져 오려고 시도합니다 UIWindow.rootViewController.

Step6 :-topMostViewController.view 원래 거리 로 복원해야하는 방해 거리를 계산 했습니다.

Step7 :-topMostViewController.view.frame 방해 거리에 따라 회복 했습니다.

Step8 :- 앱로드시 싱글 톤 IQKeyboardManager 클래스 인스턴스를 인스턴스화 했으므로 앱의 모든 UITextField/ UITextView가 예상 이동 거리에 따라 자동으로 조정됩니다.

그게 다야 IQKeyboardManager을 당신을 위해 할 코드의 NO LINE 정말! 관련 소스 파일을 프로젝트로 끌어서 놓기 만하면됩니다. IQKeyboardManager 는 또한 장치 방향 , 자동 UI 도구 모음 관리 , KeybkeyboardDistanceFromTextField 및 훨씬 더 많은 것을 지원합니다.


내 프로젝트에 IQKeyBoardManagerSwift 디렉토리를 추가했는데 작동하지 않습니다. AppDelegate에서 인식 할 수없는 cuz를 사용할 수 없습니다 ...
user3722523

2
피싱처럼 실제 솔루션이 표시되지 않지만 대신 GitHub 계정에 대한 광고가 표시됩니다.
Brian

101

필자는 키보드에서 벗어나는 모든 텍스트 필드를 이동시키는 범용 드롭 UIScrollViewUITableViewUICollectionView서브 클래스를 구성했습니다.

키보드가 나타나려고 할 때 서브 클래스는 편집 할 서브 뷰를 찾고 키보드 팝업과 일치하는 애니메이션을 사용하여 뷰가 표시되도록 프레임과 컨텐츠 오프셋을 조정합니다. 키보드가 사라지면 이전 크기로 복원됩니다.

기본적으로 모든 설정, 즉 UITableView기반 인터페이스 또는 수동으로 배치 된보기로 구성된 설정에서 작동해야합니다 .

여기 : 키보드에서 텍스트 필드를 이동시키는 솔루션


이거 야! 이것이 가장 효율적이고 완벽한 솔루션입니다! 또한 스크롤 뷰에 대한 회전을 올바르게 처리합니다. 회전하는 경우 반드시 수직으로 자동 크기를 조정하지만 하단에 고정하지 마십시오. 필자의 경우 스크롤보기에 UITextView를 추가했습니다. 고마워요!
Christopher

아주 좋은 일입니다! 물론, 나는 DIY 대신 솔루션을 사용하여 게으르고 있지만 내 상사는 더 행복합니다. 그렇습니다! 누군가가 스스로하고 싶어하더라도 각 컨트롤러에 코드를 추가하는 대신 하위 클래스 접근 방식이 마음에 듭니다. 나는 안드로이드와 같은 기본적으로이 작업을 수행하지 않은 아이폰 OS를 충격을 받았다 않았다 - 다시, 나는 :( iOS 및 맥 OS에서 부족한 것들을 많이 찾는거야
eselk

내 스크롤보기와 같은 이상한 것들이 모두 화면에 맞기 때문에 스크롤 할 수 없습니다. 키보드를 열고 닫은 후에는 내용이 더 커지고 (페이지 하단에 보이지 않는 것이 추가되고 제거되지 않은 것처럼) 스크롤 될 수 있습니다.
Almo

90

대한 스위프트 프로그래머 :

이것은 당신을 위해 모든 것을 할 것입니다. 뷰 컨트롤러 클래스에 이것을 넣고 뷰 컨트롤러에 구현 UITextFieldDelegate하고 textField의 대리자를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()
}

스위프트 4, 4.2, 5 : 변경

self.view.frame = CGRectOffset(self.view.frame, 0,  movement)

self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)

이 구현에 대한 마지막 참고 사항 : 키보드가 표시된 상태에서 다른 뷰 컨트롤러를 스택으로 푸시하면 뷰가 다시 중앙 프레임으로 되돌아 가지만 키보드 오프셋이 재설정되지 않는 오류가 발생합니다. 예를 들어, 키보드는 nameField의 첫 번째 응답자이지만 도움말보기 컨트롤러를 스택으로 푸시하는 버튼을 누릅니다. 오프셋 오류를 수정하려면 viewField를 떠나기 전에 nameField.resignFirstResponder ()를 호출하여 textFieldDidEndEditing 델리게이트 메소드도 호출해야합니다. viewWillDisappear 메소드에서이 작업을 수행합니다.


3
SwiftLint가 마음에 들지 않아서 self.view.frame = CGRectOffset(self.view.frame, 0, movement)그 줄을 다음 과 같이 변경했습니다self.view.frame.offsetInPlace(dx: 0, dy: movement)
levibostian

2
스위프트 4 self.view.frame = CGRectOffset (self.view.frame, 0, movement)를 self.view.frame.offsetBy (dx : 0, dy : movement)로 변경
Asinox

참고로, 이것이 작동하려면 넣어야합니다. self.view.frame = self.view.frame.offsetBy (dx : 0, dy : movement)
Josh Wolff

64

이미 많은 답변이 있지만, 위의 솔루션 중 "완벽한"버그가없고 이전 버전과 호환되며 깜박임이없는 애니메이션에 필요한 멋진 위치 지정 기능이 아직 없었습니다. (프레임 / 바운드 및 contentOffset을 서로 다른 인터페이스 방향, iPad 분할 키보드 등을 애니메이션 할 때의 버그)
솔루션을 공유하겠습니다 :
(설정 한 것으로 가정 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];
}

@Shiun 답변이 크게 개선되었습니다. 그러나 키보드가 사라진 후에는 뷰가 첫 번째 위치로 돌아 오지 않습니다. 그것은 여전히 ​​훌륭한 작품입니다 :)
Lucien

2
고마워, 이것은 2017 년에 나에게 가장 적합한 솔루션입니다. focusedControl을 직접 추적 할 필요가 없으므로 (으)로 결정할 수 있습니다 UIApplication.shared.sendAction(...). 다음은 Swift 3 버전의 답변입니다 (빼기 부분 제외).sendAction : 구현 gist.github.com/xaphod/7aab1302004f6e933593a11ad8f5a72d
xaphod

필자의 경우 @xaphod 더 많은 컨트롤 (예 : 입력 필드 아래의 버튼)에 집중해야했습니다. 그러나 그렇습니다.이 코드는 이제 4 살이되었으며 개선으로 혜택을 볼 수 있습니다.
Martin Ullrich

이것은 아마도 적절한 해결책입니다. 키보드 알림은 애니메이션 데이터를 전달하며 텍스트 필드 위임은 애니메이션 지속 시간에 대해 알지 못하며 추측 작업 일뿐입니다.
XY

62

Shiun 씨는 "현재 UIScrollView가 현재 편집 된 UITextField를 실제로 볼 수있는 창에 내재적으로 가져 온다고 생각한다"고 말했다. iOS> = 3.2에서 UITextField를 표시하려면 명시 적 scrollRectToVisible을 추가해야했습니다.


내재적으로 편집 된 UITextField를보기로 스크롤하는 UIScrollView가 아닙니다. UITextField 는 [UITextField scrollTextFieldToVisibleIfNecessary]호출 [UIScrollView scrollRectToVisible]될 때 호출하는 개인 메소드를 [UITextField becomeFirstResponder]호출합니다. github.com/leopatras/ios_textfields_on_scrollview를 참조하십시오 . 제약 조건과 뷰 컨트롤러가 올바르게 설정되면 실제로는 scrollRectToVisible명시 적으로 호출 할 필요가 없습니다 (적어도 IOS 11 이후).
Leo

48

고려해야 할 한 가지는 UITextField자체적 으로 사용하고 싶은지 여부 입니다. 실제로 UITextFields외부에서 사용하는 잘 설계된 iPhone 응용 프로그램을 보지 못했습니다 UITableViewCells.

추가 작업이 필요하지만 모든 데이터 입력 뷰를 테이블 뷰로 구현하는 것이 좋습니다. a를 UITextView하는 방법UITableViewCells .


1
내 앱 중 하나에서 사용자가 자유형 노트를 추가 할 수 있도록해야하므로 UITextField를 사용하는 것이 때로는 유용합니다.
피터 존슨

1
이 방법에 동의합니다. 이런 식으로 작업하거나 코딩하지 마십시오. 자유 양식 메모가 필요한 경우에도 테이블 셀을 사용할 수 있습니다
RJH

UITableView슬프게도 갈 수있는 유일한 방법입니다. 키보드 알림이 깨지기 쉬우 며 초과 근무 시간이 변경되었습니다. 스택 오버플로의 샘플 코드 : stackoverflow.com/a/32390936/218152
SwiftArchitect 22.16의

이 답변은 5 년 이 지났습니다. 유일하게 현대적인 솔루션은 다음과 같습니다 ... stackoverflow.com/a/41808338/294884
Fattie

47

문서는이 문제에 대한 해결책을 자세히 설명합니다. '키보드 아래에있는 컨텐츠 이동'에서 소스 코드를보십시오. 꽤 간단합니다.

편집 : 예제에 까다로운 결함이 있음을 알았습니다. 당신은 아마 UIKeyboardWillHideNotification대신에 듣고 싶어 할 것 입니다 UIKeyboardDidHideNotification. 그렇지 않으면 키보드 닫기 애니메이션이 지속되는 동안 키보드 뒤의 스크롤보기가 잘립니다.


32

가장 쉬운 솔루션 발견

- (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];
}

화면이 맨 아래에 있지 않더라도 위로 이동합니다. 즉, 텍스트 필드가 맨 위에 있으면 화면 밖으로 이동합니다. 그 사건을 통제하는 방법?
MELWIN

@MELWIN이 줄 다음에 추가 int movement = (up ? -movementDistance : movementDistance); if (textField.frame.origin.y < self.view.frame.size.height - keyboard.height) { movementDistance = 0 }하십시오 : keyboard변수는 다음과 같이하여 나타나는 키보드의 CGRect가 아닙니다 .let keyboard = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey]!.CGRectValue())!
CapturedTree

31

많은 UITextField에서 작동하는 작은 수정

#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]; 
}

rect.origin.y=+currTextField.frame.origin.y잘 작동 감사합니다
u.gen

30

RPDP의 코드는 텍스트 필드를 키보드 밖으로 이동시킵니다. 그러나 키보드를 사용 및 해제 한 후 상단으로 스크롤하면 상단이보기에서 위로 스크롤됩니다. 이것은 시뮬레이터와 장치에 해당됩니다. 해당 뷰의 상단에있는 내용을 읽으려면 뷰를 다시로드해야합니다.

그의 다음 코드는 시야를 다시 낮추지 않아야합니까?

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

23

뷰를 위로 이동하는 것이 올바른 방법인지 확실하지 않으며 UIScrollView의 크기를 조정하여 다른 방법으로 수행했습니다. 작은 기사 에서 자세히 설명했습니다.


기사 링크가 죽었습니다.
Teo

22

원래보기 상태로 되돌리려면 다음을 추가하십시오.

-(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];
    }
}

20

이 짧은 트릭을 시도하십시오.

- (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];
}

19

많은 솔루션이 있지만 작동하기 전에 몇 시간을 보냈습니다. 따라서이 코드를 여기에 넣습니다 (프로젝트에 붙여 넣기 만하면 수정할 필요가 없습니다).

@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;
}

추신 :이 코드가 누군가가 원하는 효과를 빠르게 만들도록 도와 주길 바랍니다. (Xcode 4.5)


안녕하십니까, [self.view addSubview : natView]에서 EXE_BAD_ACCESS를 받고 있습니다.
Bala

18

user

다시 원래보기로 되돌리려면 :

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

16

뷰 프레임을 이동할 수 있도록 스크롤 뷰가 필요하지 않습니다. viewcontroller's첫 번째 응답자 텍스트 필드를 키보드 위에 놓을 수 있도록 전체보기가 위로 올라가도록보기 의 프레임을 변경할 수 있습니다 . 이 문제가 발생했을 때 하위 클래스를 만들었습니다.UIViewController . 키보드가 알림으로 나타나는지 관찰하고 첫 번째 응답자 하위보기를 찾은 다음 (필요한 경우) 첫 번째 응답자가 키보드 위에 있도록 주보기를 위로 올립니다. 키보드가 숨겨지면 다시 원래 위치로 애니메이션이 표시됩니다.

이 서브 클래스를 사용하려면 커스텀 뷰 컨트롤러를 GMKeyboardVC 의 서브 클래스로 만들고이 기능을 상속합니다 (구현 viewWillAppear하고 viewWillDisappear슈퍼 호출 해야하는지 확인하십시오 ). 클래스는 github에 있습니다.


어떤 라이센스? 파일 중 일부에는 오픈 소스 라이센스가 있고 일부는 그렇지 않습니다.
jaime September

경고 :이 코드는 ARC 프로젝트에 적합하지 않습니다.
Almo

빌드 옵션을 추가하여 파일이 ARC가 아닌 파일임을 지정하거나 파일을 ARC로 변환하고 풀 요청을 제출할 수 있습니다.
progrmr

14

스위프트 4 .

당신은 쉽게 위아래로 이동할 수 있습니다 UITextField또는 UIView으로 UIKeyBoard연결 프로그램을Animation 여기에 이미지 설명을 입력하십시오

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet var textField: UITextField!
    @IBOutlet var chatView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        textField.resignFirstResponder()
    }

    @objc func keyboardWillChange(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y
        print("deltaY",deltaY)

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.chatView.frame.origin.y+=deltaY // Here You Can Change UIView To UITextField
        },completion: nil)
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

}

2
거의 완벽합니다. iPhone X에서는 키보드와 텍스트 필드 사이에 이상한 간격이 있습니다.
Houman

12

다음은 특정 레이아웃에 대한 해킹 솔루션입니다. 이 솔루션은 섹션을 스크롤하여 볼 수 있다는 점에서 Matt Gallagher 솔루션과 유사합니다. 저는 여전히 iPhone 개발에 익숙하지 않으며 레이아웃 작동 방식에 익숙하지 않습니다. 따라서이 해킹.

필자의 구현은 필드를 클릭 할 때 스크롤을 지원하고 사용자가 키보드에서 다음을 선택할 때 스크롤을 지원해야했습니다.

높이가 775 인 UIView가있었습니다. 컨트롤은 기본적으로 넓은 공간에 3 개 그룹으로 퍼져 있습니다. 나는 다음과 같은 IB 레이아웃으로 끝났습니다.

UIView -> UIScrollView -> [UI Components]

해킹이 온다

UIScrollView 높이를 실제 레이아웃 (1250)보다 500 단위 더 크게 설정했습니다. 그런 다음 스크롤해야 할 절대 위치와 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를위한 것이었고 내부 레이아웃 엔진을 배우는 데 며칠이 없었습니다.


12

당으로 워드 프로세서 , 아이폰 OS 3.0과 같이 UITableViewController클래스는 자동으로 크기를 조절하고 텍스트 필드의 편집 인라인 (in-line)이있을 때 그 테이블보기 위치를 변경합니다. 텍스트 필드를 안에 넣는 것만으로는 충분하지 않다고 생각합니다.UITableViewCell일부는 지적 .

에서 워드 프로세서 :

테이블 뷰 컨트롤러는 테이블 뷰 행의 인라인 편집을 지원합니다. 예를 들어 행에 편집 모드에서 텍스트 필드가 포함 된 경우 표시되는 가상 키보드 위로 편집중인 행을 스크롤합니다.


나는 같은 의견을 찾았습니다. 그래, 사실이야. 이상한 점은 하나의 UITabelViewController에서 작동하고 다른 하나에서는 작동하지 않는다는 것입니다. 그러나 구현에서 차이점을 찾을 수 없었습니다.
Morpheus78

11

여기 에서 키패드를 처리하는 가장 간단한 솔루션을 찾았습니다.

샘플 코드 아래에 복사하여 붙여 넣기하고 텍스트 필드 또는 위로 이동하려는보기를 변경하면됩니다.

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 단계

키패드 알림을 viewWillAppearviewWillDisappear 메소드에서 각각 등록 및 등록 취소 합니다.

- (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];
}

참고 : 글쎄, 이 사람 감사합니다 이 아름다운 코드 조각, 깨끗한 솔루션을 공유 한이 .

이것이 누군가에게 분명히 도움이되기를 바랍니다.


나는 이것이 최고라고 생각하지 않습니다. @Dheeraj VS의 생각은 맞습니다. 텍스트 필드가 테이블의 셀에 있으면 (테이블. 스크롤 가능 = 아니오 인 경우에도) 쉽고 자동으로 수행 수 있습니다 . 참고 : 테이블의 위치와 크기는 합리적이어야합니다. 예 :-테이블의 y 위치가 뷰의 하단에서 100으로 계산되면 300 높이 키보드가 전체 테이블과 겹칩니다. -표의 높이가 10이고 키보드가 표시 될 때 표의 텍스트 필드를 100 위로 스크롤해야하는 경우 해당 텍스트 필드는 표의 경계를 벗어납니다.
samthui7

@ samthui7 Dheeraj 답변은 tableview뿐만 아니라 TableViewController를 사용하는 경우에만 작동합니다. 때로는 적합하지 않은 제약 조건이됩니다.
Ben G

10

주제에 대한 초보자를위한 좋은 자습서를 찾고 있었으므로 여기 에서 가장 좋은 자습서를 찾았습니다 .

MIScrollView.h학습서 맨 아래에 있는 예에서 공백을 두어야합니다.

@property (nonatomic, retain) id backgroundTapDelegate;

보시다시피


안녕하세요, savagenoob, 제공된 링크에 감사드립니다. (미래) 질문에 답변 할 때 최대한 많은 정보를 제공하십시오. 간단한 링크는 취하기 쉽습니다. 대답이 간과 될 수있는 좋은 튜토리얼에 대한 링크라면 말입니다.
Maarten Bodewes

10

UITextFieldA의입니다UITableViewCell 스크롤 자동으로 설정해야합니다.

그렇지 않은 경우 테이블 뷰의 잘못된 코드 / 설정 때문일 수 있습니다.

예를 들어 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];
}

이 코드가 무엇인지 혼란 스럽습니까? 키보드가 표시되면 viewWillAppear이 호출되지 않습니다. 그리고 reloadData가려진 행이 표시 될하지 않습니다.
Adam Johns

9

이 써드 파티를 사용하면 한 줄도 쓸 필요가 없습니다.

https://github.com/hackiftekhar/IQKeyboardManager

프로젝트를 다운로드하고 프로젝트에 끌어다 놓습니다 IQKeyboardManager. 문제가 발견되면 README문서 를 읽으십시오 .

얘들 아 정말 키보드를 관리하는 두통을 제거합니다.


8

노트 :이 답변은 textField가 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에서 설정하고 shouldBeginEditing의 textView에서 설정했습니다. 어떤 이유로 UIKeyboardWillShowNotification 후에 textViewDidBeginEditing이 호출되기 때문입니다.

-(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;
}

8

이것이 스위프트를 사용하는 솔루션입니다.

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
    }

}

정답이지만 TextField와 TextView를 모두 사용할 때 문제가 없습니다. 도움이 필요하십니까?
Thiha Aung

@Thiha Aung, 소스 코드의 IBOutlet 변수가 IB에 연결되어 있습니까?
Homam

그래, 그들은 그 줄에서 UITextView를 사용하는 경우 그 오류를 가지고 well.Just로 연결되어있는 경우 (CGRectContainsPoint (aRect, self.activeTextField.frame.origin)!) {
Thiha 아웅

self.activeTextField가 0이라는 의미
Thiha Aung
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.