我可以覆盖滚动视图的自动行为以滚动到第一个响应者吗?

时间:2011-10-04 02:42:40

标签: iphone uiscrollview first-responder

我在UIScrollView中有一个UITextField(深层次)。我正在观看UIKeyboardDidShowNotification,并在手动更改第一个响应者时调用相同的代码(我可能会更改为不同的文本字段而不会暂时隐藏键盘)。在该代码中,我使用scrollRectToVisible:animated:来确保UITextField可见。

我有一个非常头疼的调试为什么这很有趣,但我现在意识到UIScrollView会自动确保第一个响应者在其范围内。我正在更改UIScrollView的框架,以便它不会隐藏在键盘后面。

但是,我的代码可能比他们的代码更聪明,因为我不仅要显示UITextField,还要显示一些附近的相关视图。如果它们合适,我会尝试展示这些观点;如果不是,我尽可能多地展示它们,但至少要确保UITextField可见。所以我想保留我的自定义代码。

自动行为会干扰我的代码。我看到的是滚动视图轻轻向上滚动,以便我的内容的下边缘可见,然后它快照到我的代码告诉它的位置。

无论如何都要阻止UIScrollView执行将第一个响应者滚动到视图中的默认功能吗?

更多信息

在查看文档时,我读到他们建议更改滚动视图的contentInset而不是frame。我改变了这一点并消除了一些不可预测的行为,但它没有解决这个特殊问题。

我认为发布所有代码并不一定有用。但这是关键的召唤和当时重要属性的价值。我将为CGRects编写4元组;我的意思是(x,y,宽度,高度)。

[scrollView scrollRectToVisible:(116.2, 71.2, 60, 243) animated:YES];

scrollView.bounds ==(0,12,320,361)

scrollView.contentInset == UIEdgeInsetsMake(0,0,118,0)

textField.frame ==(112.2,222.6,24,24)

转换为scrollView的直接子视图的坐标==(134.2,244.6,24,24)

转换为scrollView的坐标==(134.2,244.6,24,24)

因此,由于插入,滚动视图底边确实在y == 243。

请求的矩形扩展为y == 314.2。

文本字段扩展为y == 268.6。

两者都是出界的。 scrollRectToVisible试图解决其中一个问题。标准UIScrollView / UITextField行为正在尝试修复另一个。他们没有提出完全相同的解决方案。

5 个答案:

答案 0 :(得分:5)

我没有测试这种特殊情况,但我设法通过子类化scrollview并覆盖setContentOffset:和setContentOffset:animated:来阻止scrollview在顶部和底部弹跳。 scrollview在每次滚动动作时调用它,所以我很确定在滚动到文本字段时会调用它们。

您可以使用委托方法textFieldDidBeginEditing:来确定何时允许滚动。

在代码中:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    self.blockingTextViewScroll = YES;
}

-(void)setContentOffset:(CGPoint)contentOffset
{
    if(self.blockingTextViewScroll)
    {
        self.blockingTextViewScroll = NO;
    }
    else
    {
        [super setContentOffset:contentOffset];
    }
}


-(void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
{
    if(self.blockingTextViewScroll)
    {
        self.blockingTextViewScroll = NO;
    }
    else
    {
        [super setContentOffset:contentOffset animated:animated];
    }
}

如果您当前的滚动行为与setContentOffset:override一起使用,只需将其放在else块中(或者最好放在您从else块调用的方法中)。

答案 1 :(得分:2)

在我的项目中,我已经成功实现了这一点,只是在延迟一段时间后才执行滚动。

- (void)keyboardWillShow:(NSNotification *)note
{
    NSDictionary *userInfo = note.userInfo;
    CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

    UIEdgeInsets contentInsets = self.tableView.contentInset;
    contentInsets.bottom += keyboardFrame.size.height;

    [self.tableView setContentInset:contentInsets];
     [self performSelector:@selector(scrollToEditableCell) withObject:nil afterDelay:0];
}

还有其他可能性使您的视图与其他视图成为第一响应者和傻瓜滚动视图在哪里滚动。尚未测试过。

答案 2 :(得分:0)

这可能会变得毫无用处,但是您在调用scrollView.userInteractionEnabled之前尝试将scrollrectToVisible:设置为NO吗?然后将其设置回YES?它可能会阻止自动滚动行为。

答案 3 :(得分:0)

尝试将自动调整视图更改为UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin。默认值为FlexibleTopMargin所以也许这就是原因。 btw scrollRectToVisible:正在使用scrollView.contentSize

您可以尝试先更改scrollView尺寸,然后应用scrollRectToVisible:更改。第一帧改变,然后内容改变。 (也许观察键盘确实出现了事件)

答案 4 :(得分:0)

从iOS 14开始,自动滚动行为似乎特别麻烦。我通过子类化UIScrollView并重写setContentOffset来解决任何问题,从而缓解了该问题。这是我的代码的基础。

class ManualScrollView: UIScrollView {

    /// Use this function to set the content offset. This will forward the call to
    /// super.setContentOffset(:animated:)
    /// - Parameters:
    ///   - contentOffset: A point (expressed in points) that is offset from the content view’s origin.
    ///   - animated: true to animate the transition at a constant velocity to the new offset, false to make the transition immediate.
    func forceContentOffset(_ contentOffset: CGPoint, animated: Bool) {
        super.setContentOffset(contentOffset, animated: animated)
    }

    /// This function has be overriden to do nothing to block system calls from changing the
    /// content offset at undesireable times.
    ///
    /// Instead call forceContentOffset(:animated:)
    override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {

    }
}

这有效,但是您必须处理重新实现通常通常免费获得的许多滚动视图行为和方法。由于scrollRectToViewscrollToView都使用setContentOffset,因此如果您希望它们起作用,还必须重新实现它们。