【问题标题】:UIKit: UIScrollView automatically scrolling when a subview increases its width past the edge of the screenUIKit:当子视图的宽度超过屏幕边缘时,UIScrollView 会自动滚动
【发布时间】:2011-09-08 10:39:26
【问题描述】:

在 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值?

【问题讨论】:

  • 如果你能提供一个示例项目的链接会有所帮助。

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


【解决方案1】:

基本上setFrameUIScrollView 将重新调整滚动视图offset,由_adjustContentOffsetIfNecessary 完成。由于该方法是私有的并且没有记录,因此我们几乎无法猜测调整将如何发生。 有两种方法可以停止不必要的滚动或设置错误的offset

1) 在应用setFrame 后重置UIScrollView offset。如果您根据一些计算有意修改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))
}

如果这有帮助,请告诉我。

【讨论】:

  • @Hooray Im 帮助 建议有帮助吗?如果没有请更新
  • 抱歉回复时间长。这并没有解决它。我覆盖了 setContentOffset 方法并在其中有一个日志记录语句 - 它们没有被调用,这似乎表明它是一个父类进行滚动。
【解决方案2】:

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

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

【讨论】:

  • 如果归根结底,我会诉诸这样的黑客攻击,但我宁愿不这样做。无论如何,+1 是一个很好的答案。
【解决方案3】:

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

- (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 的适当值。

【讨论】:

  • 这不起作用。我已经用键盘的高度偏移了 UIScrollView 框架的高度。
猜你喜欢
  • 2021-07-05
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-17
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多