我在我的iOS应用程序中有一个UITextView,它显示大量的文本。

然后,我通过使用UITextView的offset margin参数来分页此文本。

我的问题是UITextView的填充使我的计算感到困惑,因为它似乎是不同的,取决于我使用的字体大小和字体。

是否有可能移除UITextView内容周围的填充?


当前回答

对我来说(iOS 11和Xcode 9.4.1),神奇的工作是设置textView。字体属性为UIFont.preferred(forTextStyle:UIFontTextStyle)风格,也是Fattie提到的第一个答案。但胖子的答案没有工作,直到我设置textView。字体属性。否则UITextView行为不稳定。

其他回答

做插入解决方案,我仍然有填充在右侧和底部。文本对齐也会导致问题。我找到的唯一可靠的方法是将文本视图放在另一个被剪切到边界的视图中。

对于iOS 7.0,我发现contentInset技巧不再有效。这是我在iOS 7中用来去除边距/填充的代码。

这将把文本的左边缘带到容器的左边缘:

textView.textContainer.lineFragmentPadding = 0

这将导致文本的顶部与容器的顶部对齐:

textView.textContainerInset = .zero

这两行都需要完全删除空白/填充。

所有这些答案都针对标题问题,但我想对OP问题主体中提出的问题提出一些解决方案。

文本内容大小

一个快速计算UITextView中文本大小的方法是使用NSLayoutManager:

UITextView *textView;
CGSize textSize = [textView usedRectForTextContainer:textView.textContainer].size;

这给出了总的可滚动内容,它可能比UITextView的帧大。我发现这比textView更准确。contentSize,因为它实际计算文本占用了多少空间。例如,给定一个空的UITextView:

textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)

行高

UIFont有一个属性,可以让你快速获得给定字体的行高。所以你可以快速找到文本的行高在你的UITextView:

UITextView *textView;
CGFloat lineHeight = textView.font.lineHeight;

计算可见文本大小

确定实际可见的文本数量对于处理“分页”效果很重要。UITextView有一个属性叫textContainerInset它实际上是UITextView。frame和文本本身之间的边距。要计算可视帧的实际高度,可以执行以下计算:

UITextView *textView;
CGFloat textViewHeight = textView.frame.size.height;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textHeight = textViewHeight - textInsets.top - textInsets.bottom;

确定分页大小

最后,现在你已经有了可见文本大小和内容,你可以通过从textSize中减去textHeight来快速确定你的偏移量:

// where n is the page number you want
CGFloat pageOffsetY = textSize - textHeight * (n - 1);
textView.contentOffset = CGPointMake(textView.contentOffset.x, pageOffsetY);

// examples
CGFloat page1Offset = 0;
CGFloat page2Offset = textSize - textHeight
CGFloat page3Offset = textSize - textHeight * 2

使用所有这些方法,我不需要触摸我的嵌入,我可以去插入号或文本中任何我想要的地方。

对于iOS 10,下面这行代码用于移除顶部和底部填充。

captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)

以下是胖子非常有用的答案的更新版本。 它增加了两行重要的行,帮助我在iOS 10和11上(可能在较低的版本上也是如此)让布局正常运行:

@IBDesignable class UITextViewFixed: UITextView {
    override func layoutSubviews() {
        super.layoutSubviews()
        setup()
    }
    func setup() {
        translatesAutoresizingMaskIntoConstraints = true
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0
        translatesAutoresizingMaskIntoConstraints = false
    }
}

重要的几行是两个translatesAutoresizingMaskIntoConstraints = <true/false>语句!

这令人惊讶地删除了我所有环境中的所有边缘!

虽然textView不是第一个响应器,但可能会发生一些奇怪的底边距无法使用接受的答案中提到的sizeThatFits方法解决的情况。

当敲入textView,突然奇怪的底部边缘消失了,一切看起来像它应该,但只要textView有firstResponder。

所以我在Stack Overflow上读到,启用和禁用translatesAutoresizingMaskIntoConstraints在调用之间手动设置帧/边界时确实有帮助。

幸运的是,这不仅适用于框架设置,而且还适用于夹在两个translatesAutoresizingMaskIntoConstraints调用之间的两行setup() !

例如,当在UIView上使用systemlayoutsizefiting计算视图的帧时,这是非常有用的。它会返回正确的大小(以前它没有)!

如原文所述:

不要忘记在检查器中关闭scrollEnabled !这个解决方案在故事板和运行时都能正常工作。

就是这样,现在你真的完成了!