2010-09-29 43 views
12

Tôi có một UITextView đang ngồi trên đầu UIView, và nếu tôi chạm vào nó để mở nó để chỉnh sửa, thì bàn phím sẽ chặn phần dưới cùng của khung nhìn và Tôi không thể nhìn thấy nó mặc dù tôi có thể viết trong lĩnh vực này. Tôi có thể yêu cầu UITextView có một vùng cuộn khác hoặc giải pháp là gì?Làm thế nào để có được UITextView di chuyển đúng cách khi bàn phím hiển thị

+1

trùng lặp tìm kiếm ở đây cho câu trả lời http://stackoverflow.com/questions/1126726/how-to -make-a-uitextfield-di-up-khi-bàn phím-là-hiện tại –

Trả lời

4

Cuối cùng tôi đã làm việc đó. Đây là giải pháp của tôi, các bạn có thể phát hiện ra bất kỳ lỗi nào trong thiết kế của tôi không?

@synthesize textView = _textView; 
@synthesize callbackViewController = _callbackViewController; 


-(void)keyboardWasShown:(NSNotification*)aNotification { 
    if(keyboardShown) { 
     return; 
    } 

    NSDictionary *info = [aNotification userInfo]; 

    // Get the size of the keyboard. 
    NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey]; 
    keyboardSize = [aValue CGRectValue].size; 

    // Resize the scroll view (which is the root view of the window) 
    CGRect viewFrame = [self.textView frame]; 

    orientationAtShown = orientation; 

    if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { 
     viewFrame.size.height -= keyboardSize.height; 
    } else { 
     viewFrame.size.height -= keyboardSize.width; 
    } 

    self.textView.frame = viewFrame; 

    // Scroll the active text field into view. 
    //CGRect textFieldRect = [activeField frame]; 
    [self.textView scrollRectToVisible:viewFrame animated:YES]; 

    keyboardShown = YES; 
} 

-(void)keyboardWasHidden:(NSNotification*)aNotification { 
    if(!keyboardShown) { 
     return; 
    } 

    // Reset the height of the scroll view to its original value 
    CGRect viewFrame = [self.textView frame]; 
    if(orientationAtShown == UIInterfaceOrientationPortrait || orientationAtShown == UIInterfaceOrientationPortraitUpsideDown) { 
     viewFrame.size.height += keyboardSize.height; 
    } else { 
     viewFrame.size.height += keyboardSize.width; 
    } 

    self.textView.frame = viewFrame; 

    keyboardShown = NO; 
} 

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

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWasHidden:) 
               name:UIKeyboardDidHideNotification object:nil]; 
} 

-(void)viewWillAppear:(BOOL)animated { 
    keyboardShown = NO; 
    [self registerForKeyboardNotifications]; 
} 

-(void)viewWillDisappear:(BOOL)animated { 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; 
} 

// Override to allow orientations other than the default portrait orientation. 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    if(keyboardShown) { 
     [self keyboardWasHidden:nil]; 
    } 

    orientation = interfaceOrientation; 

    CGRect viewFrame = [self.textView frame]; 
    if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { 
     if(viewFrame.size.width > viewFrame.size.height) { 
      CGRect viewFrameFixed = CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.height, viewFrame.size.width); 
      self.textView.frame = viewFrameFixed; 
     } 
    } else { 
     if(viewFrame.size.width < viewFrame.size.height) { 
      CGRect viewFrameFixed = CGRectMake(viewFrame.origin.x, viewFrame.origin.y, viewFrame.size.height, viewFrame.size.width); 
      self.textView.frame = viewFrameFixed; 
     } 
    } 


    // Return YES for supported orientations 
    return YES; 
}
+0

orientationAtShown ???? bạn đã có danh sách các thành viên dữ liệu ở đây mà không có khai báo hoặc giải thích – iOSProgrammingIsFun

4

Apple có một số code samples đối phó với tình huống chính xác này.

+0

Tôi đã thực hiện ví dụ từ liên kết, và nó hoạt động nhưng khu vực cuộn cho UITextView của tôi trở nên khá nhiều nhỏ (như 50 pixel). Bất kỳ ý tưởng tại sao? – Neigaard

+0

Kiểm tra các mặt nạ thay đổi kích thước trong Trình tạo giao diện. Tôi không chắc cài đặt phù hợp là gì, nhưng họ kiểm soát cách chế độ xem văn bản đáp ứng với các thay đổi về kích thước của cha mẹ. –

+0

Khi bạn nói thay đổi kích thước mặt nạ, sau đó bạn có ý nghĩa gì? – Neigaard

15

Một giải pháp dễ dàng là để thực hiện các UITextViewDelegate Phương pháp

- (void)textViewDidBeginEditing:(UITextView *)textView 

- (void)textViewDidEndEditing:(UITextView *)textView 

Bạn có thể làm cho UITextView Khung nhỏ hơn khi bàn phím xuất hiện và làm cho nó kích thước đầy đủ một lần nữa khi bàn phím biến mất ... như sau:

- (void)textViewDidBeginEditing:(UITextView *)textView { 
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height/1.8); 
} 

- (void)textViewDidEndEditing:(UITextView *)textView { 
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); 
} 

EDIT

Giải pháp trên không tốt ... không sử dụng !!!

Bây giờ tôi nghĩ nên thay đổi kích thước UITextView theo kích thước bàn phím và không phải với giá trị cố định ... vì kích thước bàn phím có thể thay đổi khi một ngôn ngữ khác được chọn hoặc thiết bị trở nên xoay vòng. ..of nhiên -.-

Lúc đầu, bạn phải đăng ký UIViewController của bạn hiển thị UITextView bạn nhận Keyboard Notifications:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(keyboardWasShown:) 
                name:UIKeyboardDidShowNotification object:nil]; 

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

Sau đó, bạn phải thực hiện hai phương pháp -keyboardWasShown:-keyboardWillBeHidden:.

Kích thước bàn phím thực được chứa trong đối tượng NSNotification.

- (void)keyboardWasShown:(NSNotification*)notification { 
    NSDictionary* info = [notification userInfo]; 
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; 
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - keyboardSize.height); 
} 

- (void)keyboardWillBeHidden:(NSNotification*)notification { 
    self.textView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); 
} 
+0

đây là câu trả lời đúng! –

+1

Không. Điều chỉnh contentInsets, không phải khung. – Linasses

29

Một giải pháp tốt hơn, đặc biệt dành cho iOS 7, sẽ được điều chỉnh thuộc tính nội dung inset của TextView thay vì khung của nó, theo cách này, bàn phím sẽ mờ văn bản mà rơi behinds nó giống như trong bất kỳ iOS khác 7 ứng dụng. Bạn cũng sẽ phải điều chỉnh các chỉ báo cuộn để khớp.

Mở rộng câu trả lời Lindemann của,

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

    self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0); 
    self.textView.scrollIndicatorInsets = self.textView.contentInset; 
} 

- (void)keyboardWillBeHidden:(NSNotification*)notification { 
    self.textView.contentInset = UIEdgeInsetsZero; 
    self.textView.scrollIndicatorInsets = UIEdgeInsetsZero; 
} 
+0

Cảm ơn bạn đã trả lời câu hỏi này. Điều này hoàn toàn nên được đánh dấu là câu trả lời "đúng", đặc biệt, như bạn đề cập, với những thay đổi trong iOS 7. – Mani

+0

Trong iOS 8, điều này dường như xảy ra tự động – adamF

+1

@adamF Điều này không xảy ra tự động cho tôi trong iOS 8 .. – Jacob

4

@Alejandro trên có ý tưởng đúng, nhưng mã của ông không hoạt động trong chế độ phong cảnh.Tôi đã sửa đổi phương pháp keyboardWasShown: của mình để làm việc một cách chính xác trong tất cả các định hướng:

- (void)keyboardWasShown:(NSNotification *)notification { 
    if (self.textView != nil) { 
     NSDictionary* info = [notification userInfo]; 
     CGRect keyboardRect = [self.textView convertRect:[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; 
     CGSize keyboardSize = keyboardRect.size;   

     self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0); 
     self.textView.scrollIndicatorInsets = self.textView.contentInset; 
    } 
} 
0

Mở rộng @alejandro & @Mani:

Th câu trả lời cuối cùng:

- (void)keyboardWasShown:(NSNotification *)notification { 
    if (self.textView != nil) { 
     NSDictionary* info = [notification userInfo]; 
     CGRect keyboardRect = [self.textNote convertRect:[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; 
     CGSize keyboardSize = keyboardRect.size; 

     self.textView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0); 
     self.textView.scrollIndicatorInsets = self.textView.contentInset; 
    } 
} 

- (void)keyboardWillBeHidden:(NSNotification*)notification { 

    self.textView.scrollIndicatorInsets = UIEdgeInsetsZero; 
    self.textView.scrollIndicatorInsets = UIEdgeInsetsZero; 
} 
+0

điều này không hoạt động tốt, có thể là vấn đề UIKeyboardFrameEndUserInfoKey? – slboat

2

Thêm Observer đầu tiên trong viewDidLoad.

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWasShown:) 
               name:UIKeyboardDidShowNotification object:nil]; 

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

} 

Gọi phương pháp

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

UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); 
self.textView.contentInset = contentInsets; 
self.textView.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. 
CGRect aRect = self.view.frame; 
aRect.size.height -= kbSize.height; 
if (!CGRectContainsPoint(aRect, self.textView.frame.origin)) { 
    [self.textView scrollRectToVisible:self.textView.frame animated:YES]; 
} 
} 

// Called when the UIKeyboardWillHideNotification is sent 
- (void)keyboardWasHidden:(NSNotification*)aNotification 
{ 
    UIEdgeInsets contentInsets = UIEdgeInsetsZero; 
    self.textView.contentInset = contentInsets; 
    self.textView.scrollIndicatorInsets = contentInsets; 
} 
1

nếu bạn có nhiều thì 1 trường văn bản hoặc bạn muốn giảm bớt mã của bạn sau đó thử mã này

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

    [UIView beginAnimations:nil context:NULL]; 
    [UIView setAnimationDuration:0.35f]; 
    CGRect frame = self.view.frame; 
    frame.origin.y = (self.view.frame.size.height - textField.frame.origin.y) - self.view.frame.size.height+60; 
    if (frame.origin.y<-162) { 
     frame.origin.y = -162; 
    } 
    [self.view setFrame:frame]; 
    [UIView commitAnimations]; 
} 
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField{ 
    [UIView beginAnimations:nil context:NULL]; 
    [UIView setAnimationDuration:0.35f]; 
    CGRect frame = self.view.frame; 
    frame.origin.y = 0; 
    [self.view setFrame:frame]; 
    [UIView commitAnimations]; 
    return YES; 

} 
3

Nếu bạn muốn có một đầu vào Messages App phong cách , bạn có thể sử dụng một UITextView lồng nhau (cho phép nhiều dòng văn bản). Nó sẽ giống như thế này cuối cùng:

enter image description here

Bạn bắt đầu bằng cách đặt ra một cái nhìn để giữ tất cả các quan điểm con. Ở đây màu nền của bottomView được thiết lập để phù hợp với UIKeyboardAppearanceDark. Nó nằm ở dưới cùng của màn hình.

bottomView = [UIView new]; 
bottomView.frame = CGRectMake(0, h-45, w, 45); 
bottomView.backgroundColor = [UIColor colorWithRed:0.078 green:0.078 blue:0.078 alpha:1]; 
[self.view addSubview:bottomView]; 

Sau đó, thêm vào chế độ xem nền đơn giản được tạo kiểu như UITextField điển hình và thêm UITextView làm tiểu sử cho điều đó. InputTV (UITextView) lấy chiều cao dựa trên kích thước của phông chữ. Ngoài ra, tất cả các padding được lấy ra từ inputTV sử dụng các biến textContainer.

inputTVBG = [UIImageView new]; 
inputTVBG.frame = CGRectMake(10, 8, w-90, 29); 
inputTVBG.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.1f]; 
inputTVBG.layer.cornerRadius = 4.0f; 
inputTVBG.userInteractionEnabled = true; 
inputTVBG.clipsToBounds = true; 
[bottomView addSubview:inputTVBG]; 

inputTV = [UITextView new]; 
inputTV.font = [UIFont systemFontOfSize:14.0f]; 
inputTV.frame = CGRectMake(5, 6, w-100, inputTV.font.lineHeight); 
inputTV.backgroundColor = [UIColor clearColor]; 
inputTV.keyboardAppearance = UIKeyboardAppearanceDark; 
inputTV.delegate = self; 
inputTV.autocorrectionType = UITextAutocorrectionTypeNo; 
inputTV.tintColor = [UIColor whiteColor]; 
inputTV.textColor = [UIColor whiteColor]; 
inputTV.textContainer.lineFragmentPadding = 0; 
inputTV.textContainerInset = UIEdgeInsetsZero; 
[inputTVBG addSubview:inputTV]; 

Trong ví dụ trên, tôi đã bao gồm nhãn cho biết có bao nhiêu chữ cái (tối đa/ký tự) và nút gửi.

lettersLeftLabel = [UILabel new]; 
lettersLeftLabel.frame = CGRectMake(w-70, 8, 60, 16); 
lettersLeftLabel.font = [UIFont systemFontOfSize:12.0f]; 
lettersLeftLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5f]; 
lettersLeftLabel.alpha = 0.0f; 
[bottomView addSubview:lettersLeftLabel]; 

submitButton = [UIButton new]; 
submitButton.frame = CGRectMake(w-70, 0, 60, 45); 
[submitButton setTitle:@"SUBMIT" forState:UIControlStateNormal]; 
[submitButton setTitleColor:[_peacock.applePink colorWithAlphaComponent:0.5f] forState:UIControlStateNormal]; 
[submitButton addTarget:self action:@selector(submit) forControlEvents:UIControlEventTouchUpInside]; 
[submitButton.titleLabel setFont:[UIFont boldSystemFontOfSize:14.0f]]; 
[bottomView addSubview:submitButton]; 

Thêm dòng này sớm trong mã của bạn, vì vậy bạn sẽ có được cập nhật thay đổi bàn phím:

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

Nó gọi phương thức dưới đây khi người dùng nhấp vào inputTV. Ở đây nó đặt biến 'keyboardHeight' được sử dụng sau này.

-(void)keyboardWillShow:(NSNotification *)n { 
    CGRect rect = [n.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; 
    CGRect keyboardFrame = [self.view convertRect:rect fromView:nil]; 
    keyboardHeight = keyboardFrame.size.height; 
    [self textViewDidChange:inputTV]; 
} 

Đây là đoạn mã chính đảm nhiệm mọi chuyển động và thay đổi kích thước của inputTV.

-(void)textViewDidChange:(UITextView *)textView { 

    //1. letters and submit button vars 
    int numberOfCharacters = (int)textView.text.length; 
    int minCharacters = 50; 
    int maxCharacters = 400; 
    int remainingCharacters = maxCharacters-numberOfCharacters; 

    //2. if entered letters exceeds maximum, reset text and return 
    if (remainingCharacters <= 0){ 
     textView.text = [textView.text substringToIndex:maxCharacters]; 
     numberOfCharacters = maxCharacters; 
    } 

    //3. set height vars 
    inputTV.scrollEnabled = true; 
    float textHeight = textView.contentSize.height; 
    float lineHeight = roundf(textView.font.lineHeight); 
    float additionalHeight = textHeight - lineHeight; 
    float moveUpHeight = keyboardHeight + additionalHeight; 

    //4. default letter colour is weak white 
    UIColor * letterColour = [[UIColor whiteColor] colorWithAlphaComponent:0.5f]; 
    if (numberOfCharacters < minCharacters){ //minimum threshold not met 
     lettersLeftLabel.text = [NSString stringWithFormat:@"%i", minCharacters-numberOfCharacters]; 
     letterColour = [_peacock.applePink colorWithAlphaComponent:0.5f]; 
    } else { //within range 
     lettersLeftLabel.text = [NSString stringWithFormat:@"%i/%i", numberOfCharacters, maxCharacters]; 
     if (remainingCharacters<5){ //increase alpha towards the end of range 
      letterColour = [[UIColor whiteColor] colorWithAlphaComponent:1.0f - ((float)remainingCharacters/10)]; 
     } 
    } 

    //5. hide/show letter label based on textView height 
    float letterAlpha = 0.0f; //default hide 
    if (additionalHeight > 0){ letterAlpha = 1.0f; } //if multiline, show 
    [UIView animateWithDuration:0.3f 
          delay:0.0f 
         options:UIViewAnimationOptionCurveEaseOut 
        animations:^{ 
         lettersLeftLabel.alpha = letterAlpha; 
         lettersLeftLabel.textColor = letterColour; 
        } 
        completion:^(BOOL finished){ 
        }]; 

    //6. update submit colour based on minimum threshold 
    UIColor * submitColour = [_peacock.applePink colorWithAlphaComponent:0.5f]; 
    bool enableSubmit = false; 
    if (numberOfCharacters >= minCharacters){ 
     submitColour = _peacock.applePink; 
     enableSubmit = true; 
    } 
    [submitButton setEnabled:enableSubmit]; 
    [UIView animateWithDuration:0.3f 
          delay:0.0f 
         options:UIViewAnimationOptionCurveEaseOut 
        animations:^{ 
         [submitButton setTitleColor:submitColour forState:UIControlStateNormal]; 
        } 
        completion:^(BOOL finished){ 
        }]; 



    //7. special case if you want to limit the frame size of the input TV to a specific number of lines 
    bool shouldEnableScroll = false; 
    int maxNumberOfLines = 5; //anything above this triggers the input TV to stay stationary and update its scroll 
    int actualNumberOfLines = textHeight/textView.font.lineHeight; 
    if (actualNumberOfLines >= maxNumberOfLines){ //recalculate vars for frames 
     textHeight = maxNumberOfLines * lineHeight; 
     additionalHeight = textHeight - lineHeight; 
     moveUpHeight = keyboardHeight + additionalHeight; 
     shouldEnableScroll = true; 
    } 

    //8. adjust frames of views 
    inputTV.frame = CGRectMake(5, 6, w-100, textHeight); //update immediately (parent view clips to bounds) 
    [UIView animateWithDuration:0.3f 
          delay:0.0f 
         options:UIViewAnimationOptionCurveEaseOut 
        animations:^{ 
         bottomView.frame = CGRectMake(0, h-45-moveUpHeight, w, 45+additionalHeight); 
         inputTVBG.frame = CGRectMake(10, 8, w-90, lineHeight+additionalHeight+13); 
         submitButton.frame = CGRectMake(w-70, additionalHeight, 60, 45); 
        } 
        completion:^(BOOL finished){ 
         inputTV.scrollEnabled = shouldEnableScroll; //default disable scroll here to avoid bouncing 

        }]; 


} 

Trong các phương pháp trên, đây là những gì đang xảy ra:

  1. Nếu bạn muốn thiết lập ở mức tối thiểu hoặc số ký tự tối đa, bạn có thể làm như vậy ở đây. Bạn kéo số lượng ký tự và lưu trữ dưới dạng số nguyên và tính số lượng ký tự còn lại.

  2. Nếu người dùng đã đạt đến số ký tự tối đa, hãy đặt lại văn bản textView bằng cách rút gọn về giá thầu CPC

  3. Những vars này được sử dụng để tính toán số tiền bạn cần để di chuyển BottomView của mình và cũng để thay đổi kích thước các bản xem trước của nó.

  4. Phương pháp này chỉ để thay đổi màu/văn bản của một số yếu tố giao diện người dùng. Nó không hoàn toàn cần thiết.

  5. Phương pháp này sẽ đưa các chữ cáiLeftLabel vào chế độ xem nếu bạn đang sử dụng. Nó cũng không cần thiết.

  6. Điều này chỉ cho phép nút gửi nếu đạt đến số ký tự tối thiểu. Nó thay đổi màu như một chỉ báo cho người dùng.

  7. Nếu bạn muốn giới hạn sự tăng trưởng của inputTV và các yếu tố xung quanh, bạn có thể bao gồm mã bit này. Nó đòi hỏi bạn phải thiết lập số lượng tối đa của dòng bạn muốn hiển thị. Nếu người dùng vượt quá mức tối đa, cuộn được bật lại cho inputTV, nếu không thì nó sẽ mặc định là false (quan trọng là dừng nó lại).

  8. Đây là logic thay đổi kích thước chính, di chuyển bottomView lên và thay đổi kích thước chế độ xem con của nó. Nút gửi cần phải ở trong cùng một vị trí, vì vậy hãy di chuyển xuống dưới khi phần dưới cùng phát triển.

Chú ý: Nếu bạn chỉ muốn mã barebones, bạn chỉ cần thực hiện bước 3 và 8.

Các vấn đề liên quan