У меня есть вид, который похож на приложение заметок - то есть печатать на листе бумаги с подкладкой. Чтобы одновременно выполнить прокрутку текста и бумаги, я отключил прокрутку UITextView и вместо этого поместил и мой UITextView, и мой UIImageView в UIScrollView.
Единственная проблема с этим состоит в том, что, когда пользователь печатает, текст исчезает под клавиатурой, потому что, очевидно, UIScrollView не знает, чтобы прокрутить до позиции курсора.
Есть ли какой-нибудь простой способ получить позицию курсора и сказать UIScrollView, чтобы она прокручивалась там?
--- EDIT ---
Начиная с чего-то похожего здесь (где кто-то пытался сделать что-то подобное с UITableView), мне удалось создать растущий редактируемый UITextView с фиксированным фоном, который почти прокручивает отлично. Единственные проблемы сейчас:
- При перемещении текста вверх по тексту появляется небольшое колебание.
- Если пользователь скрывает клавиатуру, выбирает текст в нижней части экрана, а затем снова показывает клавиатуру, ему нужно набрать пару букв, прежде чем текст снова станет видимым - он не прокручивается сразу.
- Когда пользователь прячет клавиатуру, анимация, когда рамка прокрутки заполняет экран, выглядит не совсем правильно.
Вот код - я был бы очень признателен, если кто-нибудь может уточнить его дальше ...
#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];
}