我想将文本垂直居中放置在UITextView
可填充整个屏幕的大文本内部-这样,当文本很少时,说几个字,就以高度为中心。这不是关于文本居中(在IB中可以找到的属性)的问题,而是关于如果文本较短则将文本垂直居中放置的问题,因此。能做到吗?提前致谢!UITextView
UITextView
我想将文本垂直居中放置在UITextView
可填充整个屏幕的大文本内部-这样,当文本很少时,说几个字,就以高度为中心。这不是关于文本居中(在IB中可以找到的属性)的问题,而是关于如果文本较短则将文本垂直居中放置的问题,因此。能做到吗?提前致谢!UITextView
UITextView
Answers:
首先,为视图加载时的contentSize
键值添加观察者UITextView
:
- (void) viewDidLoad {
[textField addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
[super viewDidLoad];
}
然后添加此方法以在contentOffset
每次contentSize
值更改时进行调整:
-(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};
}
NSStringFromSelector(@selector(contentSize))
而不是@"contentSize"
。并且不要忘记将removeObserver:forKeyPath:
try-catch语句放进去!
因为UIKit不兼容KVO,所以我决定将其实现为一个子类,UITextView
该子类在contentSize
更改时会更新。
它是Carlos答案的稍作修改的版本,它设置了contentInset
而不是contentOffset
。除了与iOS 9兼容之外,它在iOS 8.4上的bug也似乎更少。
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)
}
}
}
contentInset
我没有更新,而是尝试通过contentSize didSet
调用上述约束并且也可以通过更改约束来调整textView的大小。
scrollEnabled = true
在计算之前调用topCorrection
,如果仍然要禁止用户滚动,则还需要userInteractionEnabled = false
。另外,它是复制粘贴的辅助工具:Xcode将init
在您的子类UITextView中需要一个方法。
layoutMargins
和写var topCorrection = (bounds.size.height - contentSize.height * zoomScale + layoutMargins.top + layoutMargins.bottom) / 2.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)
}
UITextView
。这坚持自动布局。因此,我想在所有视图中将占位符垂直居中。但是,如果用户输入了文本,则占位符将被替换,并且对齐方式应还原为使用整个可用区域。垂直对齐仅适用于占位符。是否有意义?
对于iOS 9.0.2。我们将需要设置contentInset。如果我们对contentOffset进行KVO,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用作左,下和右边缘插图。确保针对您的用例也进行计算。
setTextContainerInset
而不是setContentInset
这是将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(0, topOffset)
contentOffset.y = -positiveTopOffset
}
}
我刚刚在Swift 3中创建了一个自定义的垂直居中文本视图:
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)
}
}
}
参考:https : //geek-is-stupid.github.io/2017-05-15-how-to-center-text-vertically-in-a-uitextview/
我有一个TextView,我使用与自动布局与设置lineFragmentPadding
和textContainerInset
为零。在我的情况下,以上解决方案均无效。但是,这对我有用。经过iOS 9测试
@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
tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
改为: if ([tv contentSize].height < [tv bounds].size.height) { tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect}; }
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)
}
斯威夫特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)
}
我也有这个问题,我有一个解决它UITableViewCell
用UITextView
。我在自定义UITableViewCell
子类property中创建了方法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
此解决方案对我没有任何问题,您可以尝试一下。
自动布局解决方案:
您可以尝试以下代码,而不必强制要求观察者。当视图解除分配时,观察者有时会抛出错误。您可以将此代码保存在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};
});
});
dealloc
方法中删除观察者-(void)dealloc {}
dealloc
在ARC项目中不再被允许。:)
[super dealloc];
这是NSLayoutManager
用于获取实际文本大小的简单任务NSTextContainer
class VerticallyCenteredTextView: UITextView {
override func layoutSubviews() {
super.layoutSubviews()
let rect = layoutManager.usedRect(for: textContainer)
let topInset = (bounds.size.height - rect.height) / 2.0
textContainerInset.top = max(0, topInset)
}
}
在最终计算中不要使用contentSize
和contentInset
。
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
我通过创建垂直扩展到中心高度的方法来解决此问题。
SWIFT 5:
extension UITextView {
func centerContentVertically() {
let fitSize = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
let size = sizeThatFits(fitSize)
let heightOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(0, heightOffset)
contentOffset.y = -positiveTopOffset
}
}
RubyMotion中针对iOS10的解决方案:
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