UIKit:当子视图增加其超出屏幕边缘的宽度时,UIScrollView会自动滚动

时间:2011-06-04 16:45:02

标签: iphone objective-c cocoa-touch uikit uiscrollview

在iPhone的背景下:

我的UIScrollView包含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值?

3 个答案:

答案 0 :(得分:5)

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
[self setContentOffset:scrollPoint animated:NO];

原因:如果启用了多个offset动画,则结果offset不明确。这里内部方法(_adjustContentOffsetIfNecessary)应用偏移量变化,另一个方法由代码完成。如果您尝试记录UIScrollView委托方法中应用的所有偏移量,您会注意到这一点:

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

如果有帮助,请告诉我。

答案 1 :(得分:2)

一种可能的解决方法是响应scrollViewDidScroll委托方法检查以查看是否再次隐藏UITextField,然后在必要时重新滚动。看起来有点像黑客,但听起来像UIScrollView自动滚动行为正在阻碍你的行为,如果没有办法直接影响它,唯一的选择是解决它。然而,还有一个缺点,如果你这样做,那么它似乎滚动两次。

如果自动滚动行为仅在UITextField超出屏幕边缘时发生,您还可以移动该字段以保持完全可见,如果它看起来会扩展到屏幕边缘之外

答案 2 :(得分:0)

不要更改内容偏移,而是更改滚动视图的显示框。

- (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的相应值。