在UITextView中垂直居中文本
我想把文本垂直放在一个大的UITextView
里面,这个UITextView
是填充整个屏幕的 – 所以当文本很less的时候,说一两个字,它是以高度为中心的。 这不是一个关于居中文本(在IB中可以find的属性)的问题,而是如果文本很短,那么在UITextView
中间垂直放置文本,所以在UITextView
中没有空白区域。 可以这样做吗? 提前致谢!
首先在加载视图时为UITextView
的contentSize
键值添加一个观察者:
- (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/
我也有这个问题,我解决了UITableViewCell
与UITextView
。 我在自定义的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,我用自动布局和设置lineFragmentPadding
和textContainerInset
为零。 上述解决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:
- 创build一个充当UITextView容器的UIView。
- 添加以下约束:
- 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文本,如下所示:
- 使高度为0并添加大于的约束
- 添加垂直alignment父级约束
- 添加水平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