2011-05-11 119 views
7

我有一個類似於筆記應用的視圖 - 即在一張紙上打字。爲了使文本和紙張同時滾動,我禁用了UITextView的滾動功能,而是將UITextView和UIImageView放入UIScrollView中。如何讓UIScrollView滾動到UITextView的光標位置?

唯一的問題是,當用戶鍵入時,文本在鍵盤下消失,因爲顯然UIScrollView不知道滾動到光標位置。

有沒有簡單的方法可以檢索光標位置並告訴UIScrollView在那裏滾動?

---編輯---

從類似的東西開始here(其中有人試圖做一個UITableView類似的東西),我已經成功地使越來越多,可編輯的UITextView有固定的背景差不多完美滾動。現在唯一的問題是:

  1. 如果用戶鍵入的速度特別快,文本向上移動會有輕微抖動。
  2. 如果用戶隱藏鍵盤,選擇屏幕底部的文本,然後再次顯示鍵盤,則必須在文本再次可見之前鍵入幾個字母 - 它不會立即向上滾動。
  3. 當用戶隱藏鍵盤時,作爲滾動視圖框架填充屏幕的動畫不知何故感覺不太正確。

這裏是代碼 - 我真的很感激,如果任何人都可以進一步細化它...

#import "NoteEditViewController.h" 
#import "RLWideLabelTableCell.h" 

@implementation NoteEditViewController 
@synthesize keyboardSize; 
@synthesize keyboardHideDuration; 
@synthesize scrollView; 
@synthesize noteTextView; 

// 
// Dealloc and all that stuff 
// 
- (void)loadView 
{ 
    [super loadView]; 
    UIScrollView *aScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; 
    self.scrollView = aScrollView; [aScrollView release]; 
    self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, noteTextView.frame.size.height); 
    [self.view addSubview:scrollView]; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // Get notified when keyboard is shown. Don't need notification when hidden because we are 
    // using textViewDidEndEditing so we can start animating before the keyboard disappears. 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(keyboardWasShown:) 
               name:UIKeyboardDidShowNotification object:nil]; 

    // Add the Done button so we can test dismissal of the keyboard  
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone 
     target:self 
     action:@selector(doneButton:)]; 
    self.navigationItem.rightBarButtonItem = doneButton; [doneButton release]; 

    // Add the background image that will scroll with the text 
    CGRect noteImageFrame = CGRectMake(self.view.bounds.origin.x, 
             noteTitleImageFrame.size.height, 
             self.view.bounds.size.width, 500);  

    UIView *backgroundPattern = [[UIView alloc] initWithFrame:noteImageFrame]; 
    backgroundPattern.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Notepaper-iPhone-Line"]]; 
    [self.scrollView addSubview:backgroundPattern]; 
    [self.view sendSubviewToBack:backgroundPattern]; 
    [backgroundPattern release]; 

    // Add the textView 
    CGRect textViewFrame = CGRectMake(noteImageFrame.origin.x+27, 
             noteImageFrame.origin.y-3, 
             noteImageFrame.size.width-35, 
             noteImageFrame.size.height); 

    RLTextView *textView = [[RLTextView alloc] initWithFrame:textViewFrame]; 
    self.noteTextView = textView; [textView release]; 
    self.noteTextView.font = [UIFont fontWithName:@"Cochin" size:21]; 
    self.noteTextView.backgroundColor = [UIColor clearColor]; 
    self.noteTextView.delegate = self; 
    self.noteTextView.scrollEnabled = NO; 
    [self.scrollView addSubview:self.noteTextView]; 
} 

- (void)doneButton:(id)sender 
{ 
    [self.view endEditing:TRUE]; 
} 

// When the keyboard is shown, the UIScrollView's frame shrinks so that it fits in the 
// remaining space 
- (void)keyboardWasShown:(NSNotification*)aNotification 
{ 
    NSDictionary* info = [aNotification userInfo]; 
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; 
    float kbHideDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]; 
    self.keyboardHideDuration = kbHideDuration; 
    self.keyboardSize = kbSize; 
    self.scrollView.frame = CGRectMake(self.view.bounds.origin.x, 
             self.view.bounds.origin.y, 
             self.view.bounds.size.width, 
             self.view.bounds.size.height - kbSize.height);  
} 

// When the user presses 'done' the UIScrollView expands to the size of its superview 
// again, as the keyboard disappears. 
- (void)textViewDidEndEditing:(UITextView *)textView 
{ 
    [UIScrollView animateWithDuration:keyboardHideDuration animations:^{self.scrollView.frame = self.view.bounds;}]; 
} 

// This method needs to get called whenever there is a change of cursor position in the text box 
// That means both textViewDidChange: and textViewDidChangeSelection: 
- (void)scrollToCursor 
{ 
    // if there is a selection cursor… 
    if(noteTextView.selectedRange.location != NSNotFound) { 
     NSLog(@"selectedRange: %d %d", noteTextView.selectedRange.location, noteTextView.selectedRange.length); 

     // work out how big the text view would be if the text only went up to the cursor 
     NSRange range; 
     range.location = noteTextView.selectedRange.location; 
     range.length = noteTextView.text.length - range.location; 
     NSString *string = [noteTextView.text stringByReplacingCharactersInRange:range withString:@""]; 
     CGSize size = [string sizeWithFont:noteTextView.font constrainedToSize:noteTextView.bounds.size lineBreakMode:UILineBreakModeWordWrap]; 

     // work out where that position would be relative to the textView's frame 
     CGRect viewRect = noteTextView.frame; 
     int scrollHeight = viewRect.origin.y + size.height; 
     CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1); 

     // scroll to it 
     [self.scrollView scrollRectToVisible:finalRect animated:YES]; 
    } 
} 

// Whenever the text changes, the textView's size is updated (so it grows as more text 
// is added), and it also scrolls to the cursor. 
- (void)textViewDidChange:(UITextView *)textView 
{ 
    noteTextView.frame = CGRectMake(noteTextView.frame.origin.x, 
            noteTextView.frame.origin.y, 
            noteTextView.frame.size.width, 
            noteTextView.contentSize.height); 
    self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, 
              noteTextView.frame.size.height+200); 
    [self scrollToCursor]; 
} 

// The textView scrolls to the cursor whenever the user changes the selection point. 
- (void)textViewDidChangeSelection:(UITextView *)aTextView 
{ 
    [self scrollToCursor]; 
} 

// PROBLEM - the textView does not scroll until the user starts typing - just selecting 
// it is not enough. 
- (void)textViewDidBeginEditing:(UITextView *)textView 
{ 
    [self scrollToCursor]; 
} 

回答

5

很酷,你發現我的帖子,很高興它是有幫助的!

我相信你可能無法看到,因爲這條線的底線:

CGRect finalRect = CGRectMake(1, scrollHeight, 1, 1); 

你正在創建一個1x1點框。一行文本可能是20或30個點的高度(取決於字體大小)。因此,如果您將此點滾動顯示,它可能只會顯示底線的頂部像素 - 使底線實際上不可見!如果您finalRect高一點,所以它涵蓋了整條生產線,它可能會更好地工作:

CGRect finalRect = CGRectMake(1, scrollHeight, 1, 30); 

此外,您可以一次打電話給你scrollRectToVisible代碼多次,這可能會導致「顫動」。在我的代碼中,我只運行textViewDidChangeSelection中的scrollRectToVisible,並在textViewDidChange中調整UITextView的大小(如果需要)。 UIScrollView(並通過繼承UITableView)內置支持將主動選擇的元素滾動到可見狀態,這在我測試時運行良好,只需在鍵入時調整UITextView的大小(但不是在通過觸摸選擇內部特定點時)。

+0

謝謝,Manesh!正如你所說的那樣,我剛剛改變了finalRect參數,這使得文本更加整齊地滾動到視圖中。但我所指的「底線」問題略有不同:如果我點擊屏幕的下半部分以使textView處於活動狀態,則當鍵盤出現時,它不會滾動*根本不必鍵入在滾動觸發之前書寫或移動光標。我猜這是因爲在調用'textViewDidBeginEditing'時還沒有設置東西,所以scrollToCursor方法不起作用。 – 2011-05-12 15:31:06

+0

你有可能發佈一個帶有工作代碼的示例項目嗎?另外,如果你想繼續嘗試自己調試它,我會考慮在每個函數中放置NSLog語句,並觀察它們觸發的順序,這可能會提供一些見解。根據您顯示和隱藏鍵盤的方式,某些功能可能會或可能不會被觸發。 – Manesh 2011-05-15 05:05:31

+0

謝謝Manesh - 碰巧發現了一個更簡單的解決方案。由於UITextView是UIScrollView的子類,因此我可以將代碼放在'scrollViewDidScroll:'委託方法中以移動背景圖像。所以我只需要像平常一樣滾動我的UITextView,而單獨的背景視圖就會響應它而移動。這樣,滾動行爲是完美的,因爲它是UITextView的內置行爲。感謝所有的幫助! – 2011-05-16 15:21:17

1

有沒有簡單的方法來發現屏幕座標中的任何文本或光標UITextView

你應該做的是註冊UIKeyboardWillShowNotificationUIKeyboardWillShowNotification。在回調中,您可以調整UIScrollViewsizecontentInsets,以調整鍵盤的大小。

鍵盤的大小,甚至動畫持續時間都在userInfo的通知中提供,因此您可以用一種很好的動畫形式進行操作。

你會發現更多的信息和示例代碼在這裏:http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

相關問題