在UITextView中垂直居中文本

时间:2012-09-25 21:17:57

标签: iphone objective-c ios xcode uitextview

我希望将文本垂直置于一个填满整个屏幕的大UITextView内 - 这样当文字很少时,说几句话,它就会以高度为中心。 这不是关于文本居中(可以在IB中找到的属性)的问题,而是关于将文本垂直放在UITextView 的中间,如果文字很短,所以UITextView中没有空白区域。 可以这样做吗?提前谢谢!

18 个答案:

答案 0 :(得分:60)

首先在加载视图时添加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};
}

答案 1 :(得分:46)

因为UIKit is not KVO compliant,我决定将其作为value = mapper.readValue("{\"name\":\"Bob\", \"age\":13}", MyValue.class); 的子类实现,只要UITextView发生更改,就会更新。

这是Carlos's answer的略微修改版本,它设置contentSize而不是contentInset。除了being compatible with iOS 9之外,它在iOS 8.4上似乎也不那么多了。

contentOffset

答案 2 :(得分:22)

如果您不想使用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)
}

答案 3 :(得分:20)

适用于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代表左,右和右边缘。确保为您的用例计算这些。

答案 4 :(得分:8)

这是一个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
    }

}

答案 5 :(得分:5)

斯威夫特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)

    }

答案 6 :(得分:5)

我有一个textview,我正在使用autolayout并将lineFragmentPaddingtextContainerInset设置为零。上述解决方案都不适用于我的情况。但是,这对我有用。使用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

答案 7 :(得分:5)

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)
}

答案 8 :(得分:4)

我也有这个问题,我用UITableViewCellUITextView解决了这个问题。我在自定义UITableViewCell子类中创建了方法,属性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

此解决方案对我没有任何问题,您可以尝试。

答案 9 :(得分:3)

我刚刚在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/

答案 10 :(得分:2)

自动布局解决方案:

  1. 创建一个UIView,作为UITextView的容器。
  2. 添加以下约束:
    • TextView:将前导空格与:Container
    • 对齐
    • TextView:将尾随空格对齐:Container
    • TextView:将中心Y对齐:容器
    • TextView:Equal Height to:Container,Relation:≤

答案 11 :(得分:1)

添加到Carlos的答案,以防你在电视中的文字大于电视尺寸你不需要重新输入文字,所以改变这段代码:

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

到此:

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

答案 12 :(得分:0)

你可以尝试下面的代码,没有强制要求的观察者。观察者有时会在视图释放时抛出错误。 您可以将此代码保存在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};
    });
});

答案 13 :(得分:0)

我是这样做的:首先,我将UITextView嵌入到UIView中(这也适用于mac OS)。然后我将外部UIView的所有四个边固定到其容器的两侧,使其形状和大小与UITextView的形状和大小相似或相等。因此我有一个适合UITextView的容器。然后我将UITextView的左右边框固定到UIView的两侧,并给UITextView一个高度。最后,我将UITextView垂直放在UIView中。 Bingo :)现在UITextView在UIView中垂直居中,因此UITextView内的文本也是垂直居中的。

答案 14 :(得分:0)

我通过垂直扩展到中心高度来解决此问题。

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
    }
}

答案 15 :(得分:0)

这是使用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)
    }
}

在最终计算中不要使用contentSizecontentInset

答案 16 :(得分:-1)

的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

答案 17 :(得分:-3)

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