在UITextView中垂直居中文本

Ser*_*yov 64 iphone xcode objective-c uitextview ios

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

CSo*_*naM 61

首先添加观察者,以获取加载视图时的contentSize键值UITextView:

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

然后添加此方法以在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};
}
Run Code Online (Sandbox Code Playgroud)

  • UITextView(和其他UIKit类)不保证符合KVO标准.依赖于此可能会导致您的代码在未来的iOS版本中中断.由UIKit开发团队的成员查看此帖:http://stackoverflow.com/a/6051404/357641 (9认同)
  • 这似乎在iOS 9.0.2中被破坏了.但是,存在一种解决方法.我们可以设置contentInset而不是设置contentOffset(只需将observeValueForKeyPath方法中的最后一行代码更改为):`[tv setContentInset:UIEdgeInsetsMake(topCorrect,0,0,0)];`注意:如果我们KVO contentOffset,iOS 9在最后一刻将其设置为0,覆盖对contentOffset的任何更改. (9认同)
  • 这个解决方案对我很有用; 然而,在测试我的应用程序时,我注意到如果我将此代码调用3-4次,我会崩溃.看起来你也想删除观察者.我添加了这个并修复了崩溃: - (void)viewWillDisappear:(BOOL)animated {[textField removeObserver:self forKeyPath:@"contentSize"]; 我发现这个解决方案归功于这篇文章:http://stackoverflow.com/a/7467414/81008 (3认同)
  • 这对我很有用,直到UITextView充满文本并开始滚动.然后视图会为每个新角色弹跳.我把你的代码放在if中检查内容是否高于view:if(([myView bounds] .size.height - [myView contentSize] .height)> 0) (2认同)
  • 嗯,这个解决方案似乎对我没有任何作用:/ (2认同)

Sen*_*ful 48

因为UIKit不符合KVO,所以我决定将其作为子类实现UITextView,每当contentSize更改时都会更新.

这是Carlos的答案的略微修改版本,它设置了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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 适用于iOS 9.2.只想指出必须启用滚动才能使其正常工作.如果你想以编程方式确保(可能比期望某人在故事板中正确设置它更安全),只需在计算`topCorrection`之前调用`scrollEnabled = true`,如果你仍然想要禁用用户滚动,你将还需要`userInteractionEnabled = false`.此外,副本的副本:Xcode将在您的子类UITextView中需要一个`init`方法. (3认同)

Ben*_*o85 25

如果您不想使用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);
}  
Run Code Online (Sandbox Code Playgroud)

并称之为

-(void)textViewDidChange:(UITextView *)textView{
    [self adjustContentSize:textView];
}
Run Code Online (Sandbox Code Playgroud)

每次编辑代码中的文本.不要忘记将控制器设置为代理

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)
}
Run Code Online (Sandbox Code Playgroud)


s.k*_*.ka 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];
}
Run Code Online (Sandbox Code Playgroud)

我分别使用0,0和0作为左,右和右边缘插图.确保为您的用例计算这些.


mal*_*lex 17

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

不要在最终计算中使用contentSizeand 。contentInset


Rud*_*vič 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
    }

}
Run Code Online (Sandbox Code Playgroud)


Tai*_* Le 8

我刚刚在 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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

参考:https : //geek-is-stupid.github.io/2017-05-15-how-to-center-text-vertically-in-a-uitextview/


KOT*_*IOS 7

您可以仅使用约束直接设置它:

我添加了3个约束来在约束中垂直和水平对齐文本,如下所示:

在此输入图像描述

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

在此输入图像描述

  • 这对我有用,但是添加这些约束xcode会抛出一个有些含糊不清的错误.为了使其静音,我添加了等于0的顶部和底部约束,优先级为250. (2认同)

小智 5

我也有这个问题,我用 with 解决了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 };
Run Code Online (Sandbox Code Playgroud)

并在methods中调用这个方法:

- (void)textViewDidBeginEditing:(UITextView *)textView
- (void)textViewDidEndEditing:(UITextView *)textView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Run Code Online (Sandbox Code Playgroud)

这个解决方案对我来说没有问题,你可以尝试一下。


小智 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)
}
Run Code Online (Sandbox Code Playgroud)

  • 在我的情况下不起作用.在Swift-3工作 (2认同)

use*_*195 5

我有一个textview,我正在使用自动布局和设置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
Run Code Online (Sandbox Code Playgroud)


arn*_*100 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)

    }
Run Code Online (Sandbox Code Playgroud)