UIScrollView的高度和contentOffsetanimation从底部“跳”内容

试图做一些类似于Messages.app的行为,我有一个UIScrollView并在它下面的文本字段,并尝试进行animation处理,以便当键盘出现时,所有东西都移动到键盘上方使用一个约束,而且由于自动布局, UIScrollView的高度也会改变),同时设置contentOffset滚动到底部。

代码完成想要的最终结果,但是在animation的右侧,当键盘animation开始时,滚动视图变为空白,然后内容从底部向上滚动,而不是从animation开始时的位置滚动。

animation是这样的:

 - (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]; } 

这个问题的video可以在这里find 。

谢谢!

这可能是UIKit中的一个错误。 当UIScrollViewsizecontentOffset同时发生变化时会发生这种情况。 如果在没有自动布局的情况下也会发生这种情况,那将会很有趣。

我发现了这个问题的两个解决方法。

使用contentInset(消息方法)

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

 - (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]; } 

这里self.bottomSpaceConstraintmessageComposeViewBottom Layout Guide之间的一个约束。 这个video展示了它是如何工作的。 更新1: 这是我的项目在GitHub上的来源 。 这个项目有点简化。 我应该考虑在通知中传递的选项- (void)keyboardWillShow:(NSNotification *)notif

在队列中执行更改

不是一个确切的解决scheme,但滚动工作正常,如果你把它移动到完成块:

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

键盘显示需要0.25秒,所以animation开始之间的差异可能是显而易见的。 animation也可以按相反顺序进行。

更新2:我也注意到OP的代码可以正常工作:

 CGPoint bottomOffset = CGPointMake(0, self.collectionView.contentSize.height - (self.collectionView.bounds.size.height - height)); 

但只有当contentSizeheight小于一些固定值( 在我的情况下大约800 ,但我的布局可能有点不同)。

最后,我认为Using contentInset (the Messages approach)呈现Using contentInset (the Messages approach)比调整UICollectionView大小UICollectionView 。 当使用contentInset我们也可以看到键盘下的元素。 它当然更适合iOS 7风格。

我有一个类似的问题 – animation框架和偏移的内容将“跳”恰好animation到位之前 – 而整体解决scheme只是将UIViewAnimationOptionBeginFromCurrentState添加到animation选项。 瞧!

setNeedsUpdateConstraints是否真的需要? 是不是自动布局做自动?

如果不是,我会build议你单独resize的animation而不使用自动布局。 看起来问题是,当你试图同时做两个animation(但它不是在同一时间)

尝试删除[self.view layoutIfNeeded]行,看看问题是否仍然存在,或者是否出现其他问题,如果是这样,如果他们看起来相关的任何方式。

另外,在animation之前重置视图的位置总是一个好主意。 因此,尝试在animation行之前设置正常偏移量(甚至可以调用layoutIfNeeded方法),在开始animation之前按顺序放置所有东西。

我不确定这正是你想要的行为,但也许它可以给你一个正确的方向: Github项目

我所做的是设置两个约束,一个用于文本字段(到底部指南),另一个用于滚动视图(到文本字段)。

然后,在调用animation时,我将这两个元素的“center”属性(而不是contentOffset)设置为animation,并分别处理animation值和约束值。

最终结果在这里:

Youtubevideo

我有同样的问题,我能够通过注册NSNotifications键盘/隐藏和显示来解决它。 我正在提供相同的代码。 希望它会帮助你。

只需在你的.h类中声明BOOL isMovedUp即可

在ViewDidLoad中

 // registering notifications for keyboard/hiding and showing [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide) name:UIKeyboardWillHideNotification object:nil]; } #pragma mark-keyboard notifications - (void)keyboardWillShow { // Animate the current view out of the way if (isMovedUp==YES){ } else { [self setViewMovedUp:YES]; isMovedUp=YES; } } - (void)keyboardWillHide { if (isMovedUp==YES) { [self setViewMovedUp:NO]; isMovedUp=NO; } } //method for view transformation -(void)setViewMovedUp:(BOOL)movedUp { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.5]; // if you want to slide up the view CGRect rect = self.winePopUpView.frame; if (movedUp) { //isKeyBoardDown = NO; // 1. move the view's origin up so that the text field that // will be hidden come above the keyboard // 2. increase the size of the view so that the area // behind the keyboard is covered up. rect.origin.y -= 100; //rect.size.height += 100; } else { // revert back to the normal state. rect.origin.y += 100; //rect.size.height -= 100; //isKeyBoardDown = YES; } self.winePopUpView.frame = rect; [UIView commitAnimations]; }