UIKit: UIScrollView автоматически прокручивается, когда subview увеличивает свою ширину за краем экрана

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

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

Когда редактируемое 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 самого себя при автоматической прокрутке?

+13
04 июн. '11 в 16:45
источник поделиться
3 ответа

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

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

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

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

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

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

Позвольте мне знать, если это помогает.

+5
12 июн. '11 в 8:18
источник

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

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

+2
17 июн. '11 в 1:30
источник
другие ответы

Связанные вопросы


Похожие вопросы

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

- (void)keyboardWill:(NSNotification*)notification
{
    CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
    // Update the scroll view 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 на основе ориентации.

0
05 июн. '11 в 18:57
источник

Посмотрите другие вопросы по меткам или Задайте вопрос