UITextView内容偏移量在设置完帧后发生变化

我正在build立一个非常类似于消息应用程序的视图 – 我有一个UITextView的页面底部的子视图,当用户键入和到达行的末尾的文本视图以及包含视图它应该向上扩展。

我有它的工作方式是在textViewDidChange:方法我打电话给我的布局function,这样做

 CGFloat textViewWidth = 200; CGFloat textViewHeight = [self.textView sizeThatFits:CGSizeMake(textViewWidth, 2000)].height; [self resizeParentWithTextViewSize:CGSizeMake(textViewWidth, textViewHeight)]; // And then the resize parent method eventually calls textView.frame = CGRectMake(10, 10, textViewWidth, textViewHeight); 

问题是,当在行尾input并且视图展开时,我最终在文本视图中产生了类似于10.5的任意contentOffset.y ,所以文本全部移动到视图的顶部。 奇怪的是,它在每隔一行都是交替的,所以第一次扩展会使y内容偏移向上移动,然后在下一行接近零,然后返回到下一行的10.5,等等(不确定是否有帮助或只是我的价值观的一个奇怪的人工制品)。 之后我可以将它设置回零,但是看起来很糟糕,因为有一个短暂的闪光,文本有偏移值,然后它被移回到中间。

我读过通常使用滚动视图的内容插入而不是改变框架,但是我不知道如何去做,因为我也需要改变框架的大小。

如何在不发生这种情况下调整UITextView大小? 我想我可以通过设置文本视图不滚动,并解决了这个问题,但我想了解是怎么回事。

问题是UITextView的滚动animation和帧设置动作是同时发生的。 UITextView内部滚动当前键入的文本,以便在行尾键入一个或多个字符,或者键入新行字符。 但滚动animation不需要,因为你正在扩大textview。 不幸的是,我们不能控制textview的内部滚动动作,所以文字奇怪地滚动到扩展的textview的顶部。 而那个奇怪的滚动也使不必要的底部填充。

你可以通过覆盖UITextView的setContentOffset:animated来避免这个奇怪的操作:像这样。

Objective-C的

 - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated { [super setContentOffset:contentOffset animated:NO]; } 

迅速

 override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) { super.setContentOffset(contentOffset, animated: false) } 

这个代码避免了自动调整UITextView的不必要的滚动animation,你可以自由地扩大文本视图的大小。

设置textView.scrollable = NO可以让我调整文本视图的大小,而不会有任何奇怪的偏移,这是我唯一能find的方法。 我想这对常见场景没有太大的限制,如果你希望文本视图可以滚动,你可能不需要随时调整它的大小,因为用户可以随着内容的变化而滚动。

我遇到了同样的问题:改变UITextView的框架以适应其内容对滚动位置是错误的副作用。 即使contentSize符合boundsUITextView也会滚动。

我最终将scrollEnabled设置为true ,如果UITextView实际上不可滚动

 override var contentOffset: CGPoint { didSet { if iOS8 { // here the contentOffset may become non zero whereas it shouldn't be if !isContentScrollable && contentOffset.y > 0 { contentOffset.y = 0 } } } } var isContentScrollable: Bool { let result = ceil(contentSize.height) > ceil(height) return result } 

其实,我面临同样的问题,并发现实际上这只发生在UITextView有任何Autolay约束。 如果你会尝试使用UITextView而不应用任何约束,那么这将不会发生,并会正常工作。 但是,当您应用自动布局约束时,它会自动滚动到底部。 为了处理这个我只是添加方法

 -(void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; self.textView.contentOffset = CGPointZero; }