高度和contentOffset的UIScrollView动画从底部"跳转"内容

aby*_*byx 12 core-animation objective-c uiscrollview ios autolayout

尝试做类似于Messages.app的行为,我UIScrollView在它下面有一个文本字段,并尝试对其进行动画处理,以便当键盘出现时,所有内容都会使用一个向上移动字段的约束向上移动(和所述UIScrollView的高度变化,以及由于自动版式),并且还设置contentOffset在同一时间滚动到底部.

代码完成了所需的最终结果,但在动画期间,当键盘动画开始时,滚动视图变为空白,然后内容从底部向上滚动,而不是从动画开始时的位置滚动.

动画是这样的:

- (void)updateKeyboardConstraint:(CGFloat)height animationDuration:(NSTimeInterval)duration {
    self.keyboardHeight.constant = -height;
    [self.view setNeedsUpdateConstraints];

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        [self.view layoutIfNeeded];
        self.collectionView.contentOffset = 
            CGPointMake(0, self.collectionView.contentSize.height - self.collectionView.bounds.size.height);
    } completion:nil];
}
Run Code Online (Sandbox Code Playgroud)

此处提供了该问题的视频.

谢谢!

Are*_*lko 34

它可能是UIKit中的一个错误.它发生时,有一个同步变化sizecontentOffsetUIScrollView.测试在没有自动布局的情况下是否也会发生此行为会很有趣.

我找到了两个解决这个问题的方法.

使用contentInset(消息方法)

正如在消息应用程序中可以看到的那样,UIScrollView当显示键盘时,高度不会改变 - 消息在键盘下可见.你可以用同样的方式做到这一点.删除UICollectionView包含UITextFieldUIButton(我将称之为messageComposeView)的视图之间的约束.然后在UICollectionView和之间添加约束Bottom Layout Guide.保留的约束messageComposeViewBottom Layout Guide.然后contentInset用来保持UICollectionView键盘上方的最后一个元素.我是通过以下方式做到的:

- (void)updateKeyboardConstraint:(CGFloat)height animationDuration:(NSTimeInterval)duration {
    self.bottomSpaceConstraint.constant = height;

    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        CGPoint bottomOffset = CGPointMake(0, self.collectionView.contentSize.height - (self.collectionView.bounds.size.height - height));
        [self.collectionView setContentOffset:bottomOffset animated:YES];

        [self.collectionView setContentInset:UIEdgeInsetsMake(0, 0, height, 0)];

        [self.view layoutIfNeeded];
    } completion:nil];
}
Run Code Online (Sandbox Code Playgroud)

self.bottomSpaceConstraintmessageComposeView和之间的约束Bottom Layout Guide.这是显示其工作原理的视频. 更新1: 这是我在GitHub上的项目源代码.这个项目有点简化.我应该考虑通知中传递的选项- (void)keyboardWillShow:(NSNotification *)notif.

在队列中执行更改

不是一个确切的解决方案,但如果将其移动到完成块,滚动工作正常:

} completion:^(BOOL finished) {
    [self.collectionView setContentOffset:CGPointMake(0, self.collectionView.contentSize.height - self.collectionView.bounds.size.height) animated:YES];
}];
Run Code Online (Sandbox Code Playgroud)

键盘显示需要0.25秒,因此动画的开头之间的差异可能会很明显.动画也可以按相反顺序完成.

更新2:我也注意到OP的代码可以正常使用这个变化:

CGPoint bottomOffset = CGPointMake(0, self.collectionView.contentSize.height - (self.collectionView.bounds.size.height - height));
Run Code Online (Sandbox Code Playgroud)

但只有当contentSizes height小于某个固定值时(在我的情况下800,我的布局可能会略有不同).

最后我认为我提出的方法Using contentInset (the Messages approach)比调整大小更好UICollectionView.使用时contentInset我们也可以获得键盘下元素的可见性.它当然更适合iOS 7风格.


Dan*_*anM 8

我有一个类似的问题 - 当动画帧和偏移内容将在动画到位置之前"跳" - 并且整个解决方案只是添加UIViewAnimationOptionBeginFromCurrentState到动画选项.瞧!