在UITextView中垂直居中文本

我想把文本垂直放在一个大的UITextView里面,这个UITextView是填充整个屏幕的 – 所以当文本很less的时候,说一两个字,它是以高度为中心的。 这不是一个关于居中文本(在IB中可以find的属性)的问题,而是如果文本很短,那么在UITextView中间垂直放置文本,所以在UITextView中没有空白区域。 可以这样做吗? 提前致谢!

首先在加载视图时为UITextViewcontentSize键值添加一个观察者:

 - (void) viewDidLoad { [textField addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL]; [super viewDidLoad]; } 

然后添加此方法以在contentSize值每次更改时调整contentOffset

 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { UITextView *tv = object; CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0; topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect ); tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; } 

由于UIKit不符合KVO标准 ,因此我决定将其作为UITextView的子类来实现,只要contentSize发生变化,它就会更新。

这是一个卡洛斯的答案略有修改版本设置contentInset而不是contentOffset 。 除了与iOS 9兼容之外,它在iOS 8.4上似乎也不那么麻烦。

 class VerticallyCenteredTextView: UITextView { override var contentSize: CGSize { didSet { var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0 topCorrection = max(0, topCorrection) contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0) } } } 

对于iOS 9.0.2。 我们需要设置contentInset。 如果我们将KVO设置为contentOffset,那么iOS 9.0.2会在最后一刻将其设置为0,并覆盖对contentOffset的更改。

 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { UITextView *tv = object; CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0; topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect ); [tv setContentInset:UIEdgeInsetsMake(topCorrect,0,0,0)]; } - (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:NO]; [questionTextView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL]; } 

我分别对左边,右边和右边的插图使用了0,0和0。 确保计算这些以及您的用例。

如果您不想使用KVO,则还可以手动调整偏移量,并将此代码导出到如下函数中:

 -(void)adjustContentSize:(UITextView*)tv{ CGFloat deadSpace = ([tv bounds].size.height - [tv contentSize].height); CGFloat inset = MAX(0, deadSpace/2.0); tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right); } 

并把它叫来

 -(void)textViewDidChange:(UITextView *)textView{ [self adjustContentSize:textView]; } 

每次你编辑代码中的文字。 不要忘记将控制器设置为代表

Swift 3版本:

 func adjustContentSize(tv: UITextView){ let deadSpace = tv.bounds.size.height - tv.contentSize.height let inset = max(0, deadSpace/2.0) tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right) } func textViewDidChange(_ textView: UITextView) { self.adjustContentSize(tv: textView) } 
 func alignTextVerticalInTextView(textView :UITextView) { let size = textView.sizeThatFits(CGSizeMake(CGRectGetWidth(textView.bounds), CGFloat(MAXFLOAT))) var topoffset = (textView.bounds.size.height - size.height * textView.zoomScale) / 2.0 topoffset = topoffset < 0.0 ? 0.0 : topoffset textView.contentOffset = CGPointMake(0, -topoffset) } 

Swift 3:

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() textField.frame = self.view.bounds var topCorrect : CGFloat = (self.view.frame.height / 2) - (textField.contentSize.height / 2) topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect textField.contentInset = UIEdgeInsetsMake(topCorrect,0,0,0) } 

我刚刚在Swift 3中创build了一个自定义垂直居中的文本视图:

 class VerticallyCenteredTextView: UITextView { override var contentSize: CGSize { didSet { var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0 topCorrection = max(0, topCorrection) contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0) } } } 

ref: http : //geek-is-stupid.github.io/blog/2017/03/14/how-to-center-text-vertically-in-a-uitextview/

我也有这个问题,我解决了UITableViewCellUITextView 。 我在自定义的UITableViewCell子类中创build了方法,属性statusTextView

 - (void)centerTextInTextView { CGFloat topCorrect = ([self.statusTextView bounds].size.height - [self.statusTextView contentSize].height * [self.statusTextView zoomScale])/2.0; topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect ); self.statusTextView.contentOffset = (CGPoint){ .x = 0, .y = -topCorrect }; 

并在方法中调用此方法:

 - (void)textViewDidBeginEditing:(UITextView *)textView - (void)textViewDidEndEditing:(UITextView *)textView - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

这个解决scheme对我没有任何问题,你可以试试。

我有一个textview,我用自动布局和设置lineFragmentPaddingtextContainerInset为零。 上述解决scheme都没有在我的情况下工作。 但是,这对我有用。 经过iOS 9testing

 @interface VerticallyCenteredTextView : UITextView @end @implementation VerticallyCenteredTextView -(void)layoutSubviews{ [self recenter]; } -(void)recenter{ // using self.contentSize doesn't work correctly, have to calculate content size CGSize contentSize = [self sizeThatFits:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)]; CGFloat topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0; self.contentOffset = CGPointMake(0, -topCorrection); } @end 

这是一个垂直居中内容的UITextView扩展:

 extension UITextView { func centerVertically() { let fittingSize = CGSize(width: bounds.width, height: CGFloat.max) let size = sizeThatFits(fittingSize) let topOffset = (bounds.size.height - size.height * zoomScale) / 2 let positiveTopOffset = max(1, topOffset) contentOffset.y = -positiveTopOffset } } 

添加到卡洛斯的答案,以防万一你有更大的电视文字电视大小,你不需要更新文本,所以改变这个代码:

 tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; 

对此:

 if ([tv contentSize].height < [tv bounds].size.height) { tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; } 

自动布局解决scheme:

  1. 创build一个充当UITextView容器的UIView。
  2. 添加以下约束:
    • TextView:将前导空间alignment到:Container
    • TextView:将尾随空间alignment到:Container
    • TextView:将中心Yalignment到:Container
    • TextView:高度等于:容器,关系:≤

你可以尝试下面的代码,没有强制要求的观察者。 观察者有时会在视图释放时抛出错误。 你可以保持这个代码在viewDidLoad,viewWillAppear或viewDidAppear任何地方。

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_main_queue(), ^(void) { UITextView *tv = txtviewDesc; CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0; topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect ); tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; }); }); 

我这样做:首先,我将UITextViewembeddedUIView(这也适用于Mac OS)。 然后我把外部UIView的所有四边固定到它的容器的边上,给它一个类似于UITextView的形状和大小。 因此,我有一个UITextView适当的容器。 然后我把UITextView的左右边框固定到UIView的边上,并给UITextView一个高度。 最后,我将UITextView垂直居中放置在UIView中。 Bingo :)现在UITextView在UIView中垂直居中,因此UITextView中的文本也是垂直居中的。

我正在用Swift3编写这个答案

我添加了3个约束,用于在约束中垂直和水平alignment文本,如下所示:

在这里输入图像描述

  1. 使高度为0并添加大于的约束
  2. 添加垂直alignment父级约束
  3. 添加水平alignment父级约束

在这里输入图像描述

的UITextView + VerticalAlignment.h

 // UITextView+VerticalAlignment.h // (c) The Internet 2015 #import <UIKit/UIKit.h> @interface UITextView (VerticalAlignment) - (void)alignToVerticalCenter; - (void)disableAlignment; @end 

的UITextView + VerticalAlignment.m

 #import "UITextView+VerticalAlignment.h" @implementation UITextView (VerticalAlignment) - (void)alignToVerticalCenter { [self addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { UITextView *tv = object; CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0; topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect ); tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; } - (void)disableAlignment { [self removeObserver:self forKeyPath:@"contentSize"]; } @end 

RubyMotion中iOS10的解决scheme:

 class VerticallyCenteredTextView < UITextView def init super end def layoutSubviews self.recenter end def recenter contentSize = self.sizeThatFits(CGSizeMake(self.bounds.size.width, Float::MAX)) topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0; topCorrection = 0 if topCorrection < 0 self.contentInset = UIEdgeInsetsMake(topCorrection, 0, 0, 0) end end