2009-12-29 18 views
10

Tôi đang sử dụng UITextView để nhân bản gần như hộp văn bản SMS phía trên bàn phím. Tôi đang sử dụng một UITextView thay vì một trường để nó có thể mở rộng với nhiều dòng.Cách di chuyển đề xuất sửa UITextView phía trên văn bản

Vấn đề là, trong UITextView của tôi, các đề xuất sửa chữa bật lên bên dưới văn bản, khiến chúng bị che khuất một phần bởi bàn phím.

Trong ứng dụng SMS, các đề xuất bật lên phía trên văn bản. Vị trí này dường như không phải là thuộc tính của UITextView hoặc UITextInputTraits.

Bất kỳ ý tưởng nào để sao chép hành vi này? Cảm ơn!

+0

Chỉ có hai lựa chọn: 1) sử dụng phương thức riêng hoặc 2) di chuyển UITextView của bạn đủ cao để bong bóng chỉnh sửa của bạn không bị che khuất. – bentford

Trả lời

8

Vấn đề là bàn phím được thực hiện như một UIWindow riêng biệt, chứ không phải hơn là một khung nhìn trong UIWindow chính, do đó, bố trí với nó là khó khăn. Dưới đây là một số gợi ý đi đúng hướng:

  • Hunt thông qua sở hữu -windows của ứng dụng để tìm ra tin UITextEffectsWindow cửa sổ và tìm ra khung của nó. Đây là bàn phím
  • Lướt qua các bản xem phụ của TextView để tìm chế độ xem UIAutocorrectInlinePrompt riêng tư. Đây là bong bóng tự động sửa lỗi.
  • Di chuyển chế độ xem phụ đó thành chế độ xem trình bao bọc riêng biệt (được thêm vào TextView) và sau đó di chuyển chế độ xem trình bao bọc đó để phía trên cửa sổ bàn phím được đề cập ở trên.

Bạn sẽ nhận thấy hai đề cập "riêng tư" ở trên. Điều đó mang tất cả các cảnh báo có liên quan. Tôi không biết tại sao Apple đã cho phép vấn đề tồn tại khi thậm chí các ứng dụng của họ đã phải làm việc xung quanh nó.

+1

Tôi tự hỏi ... đang duyệt qua các cuộc phỏng vấn mà không đề cập rõ ràng đến các lớp học tư nhân được coi là vi phạm? Tôi có nghĩa là, tôi giả sử nó mở rộng UIView phải không? Nếu tôi chỉ tìm kiếm thông qua cây của UIViews và thay đổi vị trí của một trong số họ? Không có vẻ "riêng tư" đối với tôi, nhưng có lẽ Apple không đồng ý ... – DougW

+0

Các bản xem trước chuyển tiếp hoàn toàn dựa trên các API công khai. Nhưng không có vấn đề gì bạn sẽ gió lên dựa vào hành vi không có giấy tờ. Mối nguy hiểm chính ở đây là bản cập nhật có thể làm hỏng bạn, vì vậy trong mã sản xuất tôi muốn thất bại một cách duyên dáng. Tôi sẽ không xem xét một trong các lớp con riêng tư này để ổn định mạnh mẽ, vì chúng đều hơi sôi nổi, và những điều thú vị ăn nhiều khả năng được thiết kế lại bởi Apple. Tin tưởng rằng nó hay không, Apple không làm cho mọi thứ riêng tư chỉ có nghĩa là :) Rất thường xuyên, họ là những điều Apple có kế hoạch refactor. Cho nó những gì xứng đáng. –

+0

Tình cờ bạn có mã mẫu nào không? Tôi tò mò nếu bạn sử dụng phương pháp swizzling hoặc những gì bạn có thể đã thực hiện để thực sự này ... – marcc

0

Nếu dưới cùng của UITextView của bạn xóa bàn phím, bạn sẽ có thể chỉ cần thay đổi kích cỡ UITextView của bạn đủ cao để xem các chỉnh sửa. Bản thân các chỉnh sửa không hiển thị bên ngoài khung của UITextView.

Nếu bạn muốn bắt chước những gì bạn đang nhận được trong ứng dụng SMS (sửa đổi ở trên), có thể bạn sẽ phải cuộn của riêng bạn.

-2

Đảm bảo đại biểu bộ điều khiển chế độ xem đang nghe thông báo khi bàn phím bật lên để bạn thay đổi kích thước UITextView để bàn phím không che khuất UITextView. Sau đó, chỉnh sửa của bạn sẽ không bị che khuất bởi bàn phím. Xem:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/12641-uitextview-scroll-while-editing.html

Đây là một bản sao của mã từ trang đó trong trường hợp liên kết ban đầu bị phá vỡ:

// the amount of vertical shift upwards keep the Notes text view visible as the keyboard appears 
#define kOFFSET_FOR_KEYBOARD     140.0 

// the duration of the animation for the view shift 
#define kVerticalOffsetAnimationDuration  0.50 

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

- (IBAction)backgroundClick:(id)sender 
{ 
    [latitudeField resignFirstResponder]; 
    [longitudeField resignFirstResponder]; 
    [notesField resignFirstResponder]; 

    if (viewShifted) 
    { 
     [UIView beginAnimations:nil context:NULL]; 
     [UIView setAnimationDuration:kVerticalOffsetAnimationDuration]; 

     CGRect rect = self.view.frame; 
     rect.origin.y += kOFFSET_FOR_KEYBOARD; 
     rect.size.height -= kOFFSET_FOR_KEYBOARD; 
     self.view.frame = rect; 

     [UIView commitAnimations]; 

     viewShifted = FALSE; 
    }  
} 

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView 
{ 
    if (!viewShifted) {  // don't shift if it's already shifted 

     [UIView beginAnimations:nil context:NULL]; 
     [UIView setAnimationDuration:kVerticalOffsetAnimationDuration]; 

     CGRect rect = self.view.frame;  
     rect.origin.y -= kOFFSET_FOR_KEYBOARD; 
     rect.size.height += kOFFSET_FOR_KEYBOARD; 
     self.view.frame = rect; 

     [UIView commitAnimations]; 

     viewShifted = TRUE; 
    } 
    return YES; 
} 
3

Bằng cách thực hiện tìm kiếm UIAutocorrectInlinePrompt trong bố cục bị chồng chéo hoặc bị lấn átSubViews, bạn có thể thay đổi bố cục sửa chữa để nó xuất hiện ở trên. Bạn có thể thực hiện việc này mà không cần gọi bất kỳ API riêng tư nào bằng cách tìm kiếm lượt xem của các lớp cụ thể được định vị theo cách bạn mong đợi. Ví dụ này làm việc trong đó xem là cái nào, kiểm tra để thấy rằng sửa chữa không phải là đã ở trên văn bản và di chuyển sửa chữa ở trên, và rút ra nó trên cửa sổ để nó không bị ràng buộc bởi chính UITextView. Rõ ràng nếu apple thay đổi việc triển khai cơ bản thì điều này sẽ không di chuyển được sự điều chỉnh. Thêm điều này vào việc triển khai bố cục overSubene hoặc swizzled của bạnSubViews.

- (void) moveSpellingCorrection { 
for (UIView *view in self.subviews) 
{ 
    if ([[[view class] description] isEqualToString:@"UIAutocorrectInlinePrompt"]) 
    { 
    UIView *correctionShadowView = nil; // [view correctionShadowView]; 

    for (UIView *subview in view.subviews) 
    { 
    if ([[[subview class] description] isEqualToString:@"UIAutocorrectShadowView"]) 
    { 
    correctionShadowView = subview; 
    break; 
    } 
    } 

    if (correctionShadowView) 
    { 
    UIView *typedTextView = nil; //[view typedTextView]; 
    UIView *correctionView = nil; //[view correctionView]; 

    for (UIView *subview in view.subviews) 
    { 
    if ([[[subview class] description] isEqualToString:@"UIAutocorrectTextView"]) 
    { 
     if (CGRectContainsRect(correctionShadowView.frame,subview.frame)) 
     { 
     correctionView = subview; 
     } 
     else 
     { 
     typedTextView = subview; 
     } 
    } 

    } 
    if (correctionView && typedTextView) 
    { 

    CGRect textRect = [typedTextView frame]; 
    CGRect correctionRect = [correctionView frame]; 
    if (textRect.origin.y < correctionRect.origin.y) 
    { 
     CGAffineTransform moveUp = CGAffineTransformMakeTranslation(0,-50.0); 
     [correctionView setTransform: moveUp]; 
     [correctionShadowView setTransform: moveUp]; 

     CGRect windowPos = [self convertRect: view.frame toView: nil ]; 
     [view removeFromSuperview]; 
     [self.window addSubview: view]; 
     view.frame = windowPos; 
    } 

    } 
    } 

    } 

} 
} 
+0

Cảm ơn bạn đã nhập mã. Nó chắc chắn thú vị, nhưng tôi đồng ý với một số ý kiến ​​khác rằng nó quá khó đoán để sử dụng chung. – DougW

+1

Điều này cần khắc phục - nó không tính đến hướng giao diện. – Eiko

+0

Điều này dường như hoạt động tốt, nhưng việc sửa lại khiến chế độ xem tự động sửa sang vị trí y rất thấp sau khi nhấn một phím thứ hai (tức là khi nội dung của nó được mở rộng). Bất kỳ ý tưởng tại sao? –

0

Đặt phương pháp dưới đây, điều chỉnhĐảm bảoPromptXem trong bố cụcẢnh làm việc cho tôi theo chiều dọc và ngang. Tôi có một danh mục cung cấp các phương pháp dưới cùng và trên cùng nhưng bạn sẽ có được ý tưởng.

NSArray * subviewsWithDescription(UIView *view, NSString *description) 
{ 
    return [view.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"class.description == '%@'", description]]]; 
} 

- (void) adjustAutocorrectPromptView; 
{ 
    UIView *autocorrectPromptView = [subviewsWithDescription(self, @"UIAutocorrectInlinePrompt") lastObject]; 

    if (! autocorrectPromptView) 
    { 
     return; 
    } 

    UIView *correctionShadowView = [subviewsWithDescription(autocorrectPromptView, @"UIAutocorrectShadowView") lastObject]; 

    if (! correctionShadowView) 
    { 
     return; 
    } 

    UIView *typedTextView = nil; //[view typedTextView]; 
    UIView *correctionView = nil; //[view correctionView]; 

    for (UIView *subview in subviewsWithDescription(autocorrectPromptView, @"UIAutocorrectTextView")) 
    { 
     if (CGRectContainsRect(correctionShadowView.frame,subview.frame)) 
     { 
      correctionView = subview; 
     } 
     else 
     { 
      typedTextView = subview; 
     } 
    } 

    if (correctionView && typedTextView) 
    { 
     if (typedTextView.top < correctionView.top) 
     { 
      correctionView.bottom = typedTextView.top; 
      correctionShadowView.center = correctionView.center; 
     } 
    } 
} 
1

Trên thực tế làm

textview.scrollEnabled = NO; 

sẽ thiết lập các bong bóng trên đầu trang của văn bản ... caveat là bạn mất di chuyển, trong trường hợp của tôi nó không phải là một vấn đề do havinng một textfield chỉ cho mục đích đầu vào với giới hạn ký tự

+0

+1 được kết hợp với nội dungKích thước bạn có thể tắt/bật cuộn khi cần. – EsbenB

+0

Điều đó không làm điều đó cho tôi. iOS9.3.1 chạy trên trình giả lập iPhone 6s, tôi vẫn nhận được văn bản tự động sửa dưới đây. –

+0

vâng, điều này đã được thực hiện trên sự ngạc nhiên của iOS7, tôi sẽ phải kiểm tra giải pháp này nếu nó vẫn hoạt động trên các thiết bị mới –

1

Thực ra, bàn phím đơn giản sử dụng kết quả của - [UITextInput textInputView] để xác định vị trí đặt chế độ xem chỉnh sửa (và hỏi xem chế độ xem của bạn có hỗ trợ chỉnh sửa hay không). Vì vậy, tất cả các bạn cần làm là:

- (UIView *)textInputView { 
    for (UIWindow *window in [UIApplication sharedApplication].windows) { 
    if ([window isKindOfClass:NSClassFromString(@"UITextEffectsWindow")] && 
     window != self.window) { 
     return window; 
    } 
    } 

    // Fallback just in case the UITextEffectsWindow has not yet been created. 
    return self; 
} 

Lưu ý rằng bạn sẽ có khả năng cũng cần phải cập nhật - [UITextInput firstRectForRange:] để sử dụng hệ thống của cửa sổ/thiết bị phối hợp, vì vậy bạn có thể làm điều này:

- (CGRect)firstRectForRange:(CoreTextTokenTextRange *)range { 
    CGRect firstRect = [self firstRectForRangeInternal:range]; 

    return [self convertRect:firstRect toView:[self textInputView]]; 
} 

(Trong ngữ cảnh trên, bản thân là lớp thực hiện UITextInput).

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