2009-12-29 58 views
10

我正在使用UITextView粗略複製鍵盤上方的SMS文本框。我使用的是UITextView而不是字段,因此它可以用多行進行擴展。如何將UITextView更正文本移動到文本上

問題在於,在我的UITextView中,修正建議彈出下方的文字,導致它們被鍵盤部分遮擋。

在短信應用中,建議會在文本上方彈出。該展示位置似乎不是UITextView或UITextInputTraits的屬性。

任何想法如何複製這種行爲?謝謝!

+0

只有兩個選擇:1)使用私有方法或2)移動你的UITextView足夠高,以至於你的修正氣泡不被遮擋。 – bentford 2010-01-02 01:57:13

回答

8

的問題是,鍵盤是實現爲一個獨立的UIWindow,而而不是作爲主UIWindow中的視圖,因此使用它的佈局非常棘手。下面是在正確的方向一些指針:

  • 亨特通過應用程序的-windows財產找到私人UITextEffectsWindow窗口,並計算出它的框架。這是鍵盤
  • 通過TextView的子視圖尋找專用UIAutocorrectInlinePrompt視圖。這是自動更正的泡泡。
  • 將該子視圖移動到單獨的包裝視圖(添加到TextView中),然後移動該包裝視圖,使其位於上述鍵盤窗口的上方。

你會注意到兩個提到的「私人」上面。這包含所有相關的注意事項。我不知道爲什麼蘋果公司甚至在他們的應用程序需要解決這個問題時仍然允許這個問題持續存在。

+1

我想知道......遍歷子視圖時沒有明確提到被認爲是違規的私人類?我的意思是,我認爲它擴展UIView吧?如果我偶然搜索UIViews的樹並改變其中一個的位置呢?對我來說似乎並不「私密」,但也許蘋果不同意... – DougW 2010-01-02 23:50:52

+0

橫向子視圖完全基於公共API。但不管你依靠無證行爲結束了什麼。這裏主要的危險是更新可能會破壞你,所以在生產代碼中,我想要優雅地失敗。我不會考慮這些私有子類中的任何一個是非常穩定的,因爲它們都有點時髦,並且最有可能被Apple重新設計的時髦事物。不管你信不信,蘋果公司不會將事情私人化,只是爲了表示意思:)很多時候,它們都是蘋果計劃重構的東西。把它看作是值得的。 – 2010-01-03 00:43:09

+0

偶然你有任何示例代碼?我很好奇,如果你使用方法swizzling或你可能已經做了實際實現... – marcc 2010-01-21 18:19:43

0

如果你的UITextView的底部清除了鍵盤,你應該能夠調整你的UITextView的高度,以便看到更正。更正本身不顯示在UITextView的框架之外。

如果你想模仿你在短信應用程序中獲得的內容(上面的更正),你可能不得不推出自己的。

-2

確保您的視圖控制器委託在鍵盤彈出時正在偵聽通知,以便您調整UITextView的大小以便鍵盤不會遮擋UITextView。那麼你的修正將不會被鍵盤遮掩。請參閱:

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

下面是從頁面的情況下,該代碼的副本原文鏈接被打破:

// 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

通過搜索UIAutocorrectInlinePrompt中的覆蓋或混合layoutSubViews,可以更改修正的佈局,使其顯示在上面。您可以通過查找以您期望的方式定位的特定類的子視圖來調用任何私有API。這個例子計算出哪個視圖是哪個視圖,檢查校正是否已經在文本上方,並移動上面的校正,並在窗口上繪製它,以便它不受UITextView本身限制。顯然,如果蘋果改變了底層實現,那麼這將無法糾正。將此添加到您的覆蓋或混合的layoutSubViews實現。

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

感謝您的代碼。這絕對有趣,但我同意其他一些評論,認爲它對於一般用途來說太難以預測。 – DougW 2010-02-19 00:44:55

+1

這需要修復 - 它不考慮接口方向。 – Eiko 2012-08-05 18:29:32

+0

這看起來可以正常工作,但重新引導自動更正視圖在輕按第二個鍵(即擴展其內容)後移動到非常低的y位置。任何想法爲什麼? – 2012-08-15 12:28:19

0

將下面的方法調整爲layoutSubviews中的adjustAutocorrectPromptView,它適用於縱向和橫向。我有一個類別,提供了查看底部和頂部的方法,但你明白了。

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

實際上做

textview.scrollEnabled = NO; 

將設置文本頂部的泡沫......需要注意的是,你失去滾動,於我而言,這不是一個問題,因爲havinng一個文本框僅用於具有字符限制的輸入目的

+0

+1與contentSize結合使用,您可以在需要時禁用/啓用滾動。 – EsbenB 2013-07-04 14:17:06

+0

這不適合我。運行在iPhone 6s模擬器上的iOS9.3.1,我仍然在下面獲得了自動更正文本。 – 2016-06-27 21:45:16

+0

是的,這是在iOS7的敬畏之下完成的,我將不得不檢查這個解決方案,如果它仍然適用於新設備 – 2016-12-21 14:08:53

1

實際上,鍵盤只是使用 - [UITextInput textInputView]的結果來確定修正視圖的位置(並詢問您的視圖是否支持修正)。因此,所有你需要做的是這樣的:

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

請注意,您可能還需要更新 - [UITextInput firstRectForRange:]使用座標窗口/設備的系統,所以你可以這樣做:

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

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

(在上面的上下文中,self是一個實現UITextInput的類)。