首页 文章

如何在UITextView中丢失边距/填充?

提问于
浏览
413

我的iOS应用程序中有 UITextView ,显示大量文本 . 然后我通过使用 UITextView 的偏移边距参数来分页这个文本 . 我的问题是 UITextView 的填充使我的计算混乱,因为它看起来有所不同,具体取决于我使用的字体大小和字体 .

因此,我提出了一个问题:是否可以删除 UITextView 内容周围的填充?

期待听到您的回复!

19 回答

  • 0

    对我来说(iOS 11和Xcode 9.4.1)神奇的是将textView.font属性设置为 UIFont.preferred(forTextStyle:UIFontTextStyle) 样式,也是@Fattie提到的第一个答案 . 但@Fattie的答案在我设置textView.font属性之后才起作用,否则UITextView会保持不规律的行为 .

  • 250

    2018年

    这是iOS中最愚蠢的错误之一 .

    UITextViewFixed 通常是一个合理的解决方案 .

    这是 class :

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

    不要忘记在Inspector中关闭scrollEnabled!

    • 该解决方案在故事板中可以正常工作

    • 该解决方案在运行时可以正常工作

    就是这样,你已经完成了 .

    一般来说, that should be all you need in most cases .

    即使您正在动态更改文本视图的高度,这通常也是您所需要的 .

    (动态更改高度的常见示例是在用户输入时更改它 . )

    这是来自Apple的破坏的UITextView ......

    screenshot of IB with UITextView

    这是 UITextViewFixed

    screenshot of IB with UITextViewFixed

    请注意,当然你必须

    在Inspector中关闭scrollEnabled!

    别忘了关闭scrollEnabled! :)


    一些进一步的问题

    (1)在一些不寻常的情况下 - 例如,一些具有动态变化高度的灵活单元高度表视图的情况 - Apple是世界上最令人愤怒的事情: they add extra space at the bottom . 不完全是!这必须是iOS中最令人愤怒的事情之一 .

    这是一个“快速修复”添加,这通常有助于疯狂 .

    ...
            textContainerInset = UIEdgeInsets.zero
            textContainer.lineFragmentPadding = 0
    
            // this is not ideal, but you can sometimes use this
            // to fix the "space at bottom" insanity
            var b = bounds
            let h = sizeThatFits(CGSize(
               width: bounds.size.width,
               height: CGFloat.greatestFiniteMagnitude)
           ).height
           b.size.height = h
           bounds = b
     ...
    

    (2)有时,为了解决另一个微妙的Apple麻烦,你必须添加:

    override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
        super.setContentOffset(contentOffset, animated: false)
    }
    

    (3)可以说,我们应该补充:

    contentInset = UIEdgeInsets.zero
    

    .lineFragmentPadding = 0 之后的 .lineFragmentPadding = 0 之后 . 但是......它在当前的iOS中是 just doesn't work !可能有必要在将来添加它 .

    UITextView 在iOS中完全被破坏的事实是所有移动计算中最奇怪的事情之一 .

    最后,这里有一个类似于Text Field 的提示:https://stackoverflow.com/a/43099816/294884

  • 7

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

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

    textView.textContainer.lineFragmentPadding = 0
    

    这会导致文本顶部与容器顶部对齐

    textView.textContainerInset = .zero
    

    需要两条线才能完全去除边距/填充 .

  • 742

    This workaround was written in 2009 when IOS 3.0 was released. It no longer applies.

    我遇到了完全相同的问题,最后我不得不结束使用

    nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0);
    

    其中nameField是 UITextView . 我碰巧使用的字体是Helvetica 16点 . 它只是我绘制的特定字段大小的自定义解决方案 . 这使得左偏移与左侧齐平,并且顶部偏移在我想要它的框中绘制 .

    此外,这似乎只适用于您使用默认对齐的 UITextViews ,即 .

    nameField.textAlignment = NSTextAlignmentLeft;
    

    例如,与右边对齐, UIEdgeInsetsMake 似乎对右边缘没有任何影响 .

    至少,使用.contentInset属性可以使用"correct"位置放置字段,并在不偏移 UITextViews 的情况下调整偏差 .

  • 4

    Build 一些已经给出的好答案,这里是一个纯粹的基于Interface Builder的解决方案,它利用用户定义的运行时属性并在iOS 7.0中工作:

    enter image description here

  • 11

    在iOS 5上 UIEdgeInsetsMake(-8,-8,-8,-8); 看起来效果很好 .

  • 18

    I would definitely avoid any answers involving hard-coded values, as the actual margins may change with user font-size settings, etc.

    这是@ user1687195的答案,在没有修改 textContainer.lineFragmentPadding 的情况下编写(因为docs状态这不是预期的用法) .

    This works great for iOS 7 and later.

    self.textView.textContainerInset = UIEdgeInsetsMake(
                                          0, 
                                          -self.textView.textContainer.lineFragmentPadding, 
                                          0, 
                                          -self.textView.textContainer.lineFragmentPadding);
    

    这实际上是相同的结果,只是有点清洁,因为它不会滥用lineFragmentPadding属性 .

  • 15

    Storyboard或Interface Builder解决方案,使用用户定义的运行时属性 . Update. 添加了iOS7.1和iOS6.1屏幕截图,其中包含contentInset = {{-10,-5},{0,0}}
    enter image description here

    enter image description here

  • 68

    所有这些答案都解决了 Headers 问题,但我想针对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;
    

    计算可见文本大小

    确定实际可见的文本量对于处理"paging"效果很重要 . 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
    

    使用所有这些方法,我没有碰到我的插图,我能够去插入符号或文本中我想要的任何地方 .

  • 221

    你可以使用 UITextViewtextContainerInset 属性:

    textView.textContainerInset = UIEdgeInsetsMake(10,10,10,10);

    (上,左,下,右)

  • 44

    对于iOS 10,以下行适用于顶部和底部填充删除 .

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

    这是Fattie非常有用的答案的更新版本 . 它增加了2条非常重要的线条,帮助我在iOS 10和11上完成了完美的布局(也可能在较低的版本上) .
    d

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

    The important lines are the two translatesAutoresizingMaskIntoConstraints = <true/false> statements!

    这在我所有的情况下都令人惊讶!

    虽然 textView 不是第一响应者,但可能会发生一些奇怪的底部边缘,使用接受的答案中提到的 sizeThatFits 方法无法解决 .
    当突然进入textView时,奇怪的底部边缘消失了,一切看起来都应该如此,但只有textView得到了 firstResponder .

    所以我读了here on SO,在调用之间手动设置帧/边界时,启用和禁用_1548165确实有帮助 .

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

    例如,在计算视图 using systemLayoutSizeFitting on a UIView 的帧时,这是 very helpful . 返回正确的尺寸(之前没有)!

    如在最初提到的答案:
    不要忘记在Inspector中关闭scrollEnabled!
    该解决方案在故事板以及运行时都能正常工作 .

    That's it, now you're really done!

  • 38

    For swift 4, Xcode 9

    使用以下函数可以更改UITextView中文本的边距/填充

    public func UIEdgeInsetsMake(_ top:CGFloat,_ left:CGFloat,_ bottom:CGFloat,_ right:CGFloat) - > UIEdgeInsets

    所以在这种情况下是

    self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
    
  • 2

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

  • -1

    这是一个简单的小扩展,它将从您应用中的每个文本视图中删除Apple的默认边距 .

    注意:Interface Builder仍会显示旧的边距,但您的应用程序将按预期工作 .

    extension UITextView {
    
       open override func awakeFromNib() {
          super.awakeFromNib();
          removeMargins();
       }
    
       /** Removes the Apple textview margins. */
       public func removeMargins() {
          self.contentInset = UIEdgeInsetsMake(
             0, -textContainer.lineFragmentPadding,
             0, -textContainer.lineFragmentPadding);
       }
    }
    
  • 0

    最新的斯威夫特

    self.textView.textContainerInset = .init(top:-2,left:0,bottom:0,right:0)self.textView.textContainer.lineFragmentPadding = 0

  • 3

    我找到了另一种方法,从UITextView的子视图中获取文本视图,并在子类的layoutSubview方法中进行设置:

    - (void)layoutSubviews {
        [super layoutSubviews];
    
        const int textViewIndex = 1;
        UIView *textView = [self.subviews objectAtIndex:textViewIndex];
        textView.frame = CGRectMake(
                                     kStatusViewContentOffset,
                                     0.0f,
                                     self.bounds.size.width - (2.0f * kStatusViewContentOffset),
                                     self.bounds.size.height - kStatusViewContentOffset);
    }
    
  • -4

    textView滚动也会影响文本的位置,使其看起来不是垂直居中 . 我设法通过禁用滚动并将顶部插入设置为0来使文本在视图中居中:

    textView.scrollEnabled = NO;
        textView.textContainerInset = UIEdgeInsetsMake(0, textView.textContainerInset.left, textView.textContainerInset.bottom, textView.textContainerInset.right);
    

    出于某种原因,我还没有想到它,在打字开始之前光标仍未居中,但是当我开始输入时,文本立即居中 .

  • -1
    [firstNameTextField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
    

相关问题