UIKit: UIScrollView автоматически прокручивается, когда подпредставление увеличивает свою ширину за край экрана - PullRequest
13 голосов
/ 04 июня 2011

В контексте iPhone:

У меня есть UIScrollView, содержащий UIImage. Когда пользователь нажимает на экран внутри UIImage, там, где пользователь коснулся, добавляется UITextField. Пользователь может редактировать это UITextField, и текстовое поле автоматически изменит свой размер в зависимости от того, был ли текст добавлен или удален.

Когда редактируемый a UITextField увеличивает его ширину, представление прокрутки автоматически прокручивается, чтобы показать увеличенную ширину.

Проблема возникает потому, что автоматическая прокрутка текстового поля не учитывает значение y на экране

Например, скажем, пользователь добавил текстовое поле внизу изображения. Когда они перейдут к редактированию этого текстового поля, появится клавиатура, скрывающая текстовое поле. У меня есть код для прокрутки экрана, чтобы показать текстовое поле. Проблема возникает, когда пользователь вводит столько текста, что это текстовое поле выходит за край экрана. Когда это происходит, экран прокручивается по горизонтали, чтобы вместить более широкий текст, но также и по вертикали - вертикальная прокрутка заканчивается тем, что скрывает текстовое поле, в основном сводя на нет все, что я сделал, чтобы показать текстовое поле.

Код для отображения текстового поля, если оно скрыто клавиатурой:

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

    self.offset = self.contentOffset;

    CGRect frame = self.frame;
    // self.activeField is the name of the field that is the current first responder - this just adds a little bit of padding
    frame.size.height -= keyboardSize.height + (self.activeField.frame.size.height * 2);

    if (!CGRectContainsPoint(frame, self.activeField.frame.origin)) {
        CGPoint scrollPoint = CGPointMake(self.offset.x, self.activeField.frame.origin.y - keyboardSize.height + (activeField.frame.size.height * 2));
    [self setContentOffset:scrollPoint animated:YES];
    }
}

Вот код для увеличения размера текстового поля:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    CGSize stringSize = [string sizeWithFont:textField.font];
    CGSize newSize = [newString sizeWithFont:textField.font];

    // Make textField wider if we're close to running up against it
    if (newSize.width > (textField.frame.size.width - self.widthOffset)) {
        CGRect textFieldFrame = textField.frame;
        if (stringSize.width > self.widthOffset) {
            textFieldFrame.size.width += stringSize.width;
        }
        textFieldFrame.size.width += self.widthOffset;
        textField.frame = textFieldFrame;
    }

    // Shrink the textField if there is too much wasted space
    if ((textField.frame.size.width - newSize.width) > self.widthOffset) {
        CGRect textFieldFrame = textField.frame;
        textFieldFrame.size.width = newSize.width + self.widthOffset;
        textField.frame = textFieldFrame;
    }
    return YES;
}

Вопрос в том, как заставить UIScrollView уважать само значение y при автоматической прокрутке?

Ответы [ 3 ]

5 голосов
/ 12 июня 2011

В основном setFrame из UIScrollView перенастроит вид прокрутки offset, выполненный _adjustContentOffsetIfNecessary. Поскольку этот метод является частным и не документирован, мы мало что можем догадаться о том, как произойдет корректировка. Есть два способа остановить ненужную или неправильную прокрутку offset:

1) сброс UIScrollView offset после применения setFrame. Это вы можете сделать, если вы намеренно изменяете кадр UIScrollView на основе некоторых вычислений.

CGPoint oldOffset = [scrollView contentOffset];         
scrollView.frame = CGRectMake(newFrame);
[scrollView setContentOffset:oldOffset];        

2) применить offset изменения без анимации. В вашем keyboardWasShown измените [self setContentOffset:scrollPoint animated:YES]; to<br> [self setContentOffset:scrollPoint animated:NO];

Причина: когда применяется более одного offset с включенной анимацией, результат offset неоднозначен. Здесь внутренний метод (_adjustContentOffsetIfNecessary) применяет изменение смещения, а другой выполняется вашим кодом. Вы можете заметить это, если попытаетесь зарегистрировать все смещения, применяемые в методе делегата UIScrollView:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSLog(@" offset: %@", NSStringFromCGPoint(scrollView.conentOffset))
}

Дайте мне знать, если это поможет.

2 голосов
/ 17 июня 2011

Одним из возможных способов решения этой проблемы может быть ответ на проверку метода делегата scrollViewDidScroll, чтобы проверить, не скрыт ли UITextField снова, а затем при необходимости выполнить повторную прокрутку.Похоже, что-то вроде хака, но похоже на то, что вам мешает автоматическая прокрутка UIScrollView, и если нет способа напрямую повлиять на нее, единственный вариант - обойти это.Однако есть и недостаток, заключающийся в том, что если вы сделаете это, то, по-видимому, прокрутите дважды.

Если режим автоматической прокрутки происходит только тогда, когда UITextField расширяется за край экрана, вы также можетепереместите поле, чтобы оно оставалось полностью видимым, если кажется, что оно расширяется за край экрана.

0 голосов
/ 05 июня 2011

Вместо изменения смещения содержимого измените рамку отображения представления прокрутки.

- (void)keyboardWill:(NSNotification*)notification
{
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    // Update the scroll view's frame to the region not covered by the keyboard.
    self.frame = CGRectMake(self.fullSizedFrame.origin.x, 
                            self.fullSizedFrame.origin.y, 
                            self.fullSizedFrame.size.width, 
                            self.fullSizedFrame.size.height - keyboardSize.height);
}

- (void)keyboardWillHide:(NSNotification*)notification
{
    // Set the frame back to the original frame before the keyboard was shown.
    self.frame = self.fullSizedFrame;
}

Если вы не разрешаете пользователю изменять ориентацию экрана, тогда fullSizedFrame может быть установлен в исходный кадр представления при его первом отображении. Если изменения в ориентации разрешены, вам необходимо рассчитать соответствующее значение для fullSizedFrame на основе ориентации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...