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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/746670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:48:52  来源:igfitidea点击:

How to lose margin/padding in UITextView?

iosiphonecocoa-touchuikituitextview

提问by sniurkst

I have a UITextViewin my iOS Application, which displays a large amount of text.

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

I am then paging this text by using the offset margin parameter of the UITextView.

然后我使用UITextView.

My problem is that the padding of the UITextViewis confusing my calculations as it seems to be different depending on the font size and typeface that I use.

我的问题是 的填充UITextView混淆了我的计算,因为根据我使用的字体大小和字体,它似乎有所不同。

Therefore, I pose the question: Is it possible to remove the padding surrounding the content of the UITextView?

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

Look forward to hearing your responses!

期待听到您的回复!

采纳答案by Fattie

Up-to-date for 2019

2019 年最新

It is one of the silliest bugs in iOS.

它是 iOS 中最愚蠢的错误之一。

The class given here, UITextViewFixedis a usually the most reasonable solution overall.

这里给出的类UITextViewFixed通常是最合理的整体解决方案。

Here is the class:

这是课程:

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

Don't forget to turn off scrollEnabled in the Inspector!

不要忘记在检查器中关闭 scrollEnabled !

  1. The solution works properly in storyboard

  2. The solution works properly at runtime

  1. 该解决方案在故事板中正常工作

  2. 该解决方案在运行时正常工作

That's it, you're done.

就是这样,你完成了。

In general, that should be all you need in most cases.

一般来说,在大多数情况下这应该就是您所需要的

Even if you are changing the height of the text view on the fly, UITextViewFixedusually does all you need.

即使您正在即时更改文本视图的高度,UITextViewFixed通常也能满足您的所有需求。

(A common example of changing the height on the fly, is changing it as the user types.)

(动态更改高度的一个常见示例是在用户键入时更改高度。)

Here is the broken UITextView from Apple...

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

screenshot of IB with UITextView

带有 UITextView 的 IB 屏幕截图

Here is UITextViewFixed:

这是UITextViewFixed

screenshot of IB with UITextViewFixed

带有 UITextViewFixed 的 IB 屏幕截图

Note that of course you must

请注意,您当然必须

turn off scrollEnabled in the Inspector!

在检查器中关闭 scrollEnabled!

Don't forget to turn off scrollEnabled! :)

不要忘记关闭scrollEnabled!:)



Some further issues

一些进一步的问题

(1) In some unusual cases - for example, some cases of tables with flexible, dynamically changing cell heights - Apple does a bizarre thing: They add extra space at the bottom. No, really! This would have to be one of the most infuriating things in iOS.

(1) 在一些不寻常的情况下——例如,某些表格具有灵活的、动态变化的单元格高度——Apple 做了一件奇怪的事情:它们在底部添加了额外的空间。不完全是!这一定是 iOS 中最令人恼火的事情之一。

Here is a "quick fix" to add to the above which usually helps with that madness.

这是添加到上述内容的“快速修复”,通常有助于解决这种疯狂。

...
        textContainerInset = UIEdgeInsets.zero
        textContainer.lineFragmentPadding = 0

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

(2) Sometimes, to fix yet another subtle Apple mess-up, you have to add this:

(2) 有时,要修复另一个微妙的 Apple 混乱,您必须添加以下内容:

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

(3) Arguably, we shouldbe adding :

(3) 可以说,我们应该添加:

contentInset = UIEdgeInsets.zero

just after .lineFragmentPadding = 0in UITextViewFixed.

.lineFragmentPadding = 0UITextViewFixed.

However ... believe or not ... it just doesn't workin current iOS! (Checked in 2019.) It may be necessary to add that line in the future.

然而......信不信由你......它在当前的iOS中不起作用!(于 2019 年检查。)将来可能需要添加该行。

The fact that UITextViewis broken in iOS is one of the weirdest things in all of mobile computing. Ten year anniversary of this question and it's still not fixed!

UITextView在 iOS中被破坏的事实是所有移动计算中最奇怪的事情之一。这个问题十周年了,它仍然没有解决!

Finally, here's a somewhat similar tip for TextField: https://stackoverflow.com/a/43099816/294884

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

Completely random tip: how to add the "..." on the end

完全随机提示:如何在末尾添加“...”

Often you are using a UITextView "like a UILabel". So you want it to truncate text using an ellipsis "..."

你经常使用 UITextView “像 UILabel”。因此,您希望它使用省略号“...”截断文本

If so, add a third line of code in the "setup":

如果是这样,请在“设置”中添加第三行代码:

 textContainer.lineBreakMode = .byTruncatingTail

Handy tip if you want zero height, when, there's no text at all

如果你想要零高度,当根本没有文字时的方便提示

Often you use a text view to only display text. So, the user can't actually edit anything. You use lines "0" to mean the text view will automatically change height depending on how many lines of text.

通常你使用文本视图来只显示文本。因此,用户实际上无法编辑任何内容。您使用“0”行表示文本视图将根据文本行数自动更改高度。

That's great, but if there is no text at allthen unfortunately you get the same height as if there is one line of text!! The text view never "goes away".

太好了,但是如果根本没有文字,那么不幸的是,您获得的高度与只有一行文字的高度相同!文本视图永远不会“消失”。

enter image description here

在此处输入图片说明

If you want it to "go away", just add this

如果你想让它“消失”,只需添加这个

override var intrinsicContentSize: CGSize {
    var i = super.intrinsicContentSize
    print("for \(text) size will be \(i)")
    if text == "" { i.height = 1.0 }
    print("   but we changed it to \(i)")
    return i
}

enter image description here

在此处输入图片说明

(I made it '1' so it's clear what's going on, '0' is fine.)

(我把它设为“1”,所以很清楚发生了什么,“0”很好。)

What about UILabel ?

UILabel 呢?

When just displaying text, UILabel has many advantages over UITextView. UILabel does not suffer from the problems described on this QA page. Indeed the reason we all usually "give up" and just use UITextView is that UILabel is difficult to work with. In particular it is ridiculously difficult to just add padding, correctly, to UILabel. In fact here is a full discussion on how to "finally" correctly add padding to UILabel: https://stackoverflow.com/a/58876988/294884In some cases if you are doing a difficult layout with dynamic height cells, it is sometimes better to do it the hard way with UILabel.

在只显示文本时,UILabel 比 UITextView 有很多优势。UILabel 不会遇到此 QA 页面上描述的问题。事实上,我们通常都“放弃”而只使用 UITextView 的原因是 UILabel 很难使用。特别是将padding正确地添加到 UILabel是非常困难的。事实上,这里是关于如何“最终”正确地向 UILabel 添加填充的完整讨论:https: //stackoverflow.com/a/58876988/294884在某些情况下,如果您正在使用动态高度单元进行困难的布局,有时最好用 UILabel 以艰难的方式做到这一点。

回答by user1687195

For iOS 7.0, I've found that the contentInset trick no longer works. This is the code I used to get rid of the margin/padding in iOS 7.

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

This brings the left edge of the text to the left edge of the container:

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

textView.textContainer.lineFragmentPadding = 0

This causes the top of the text to align with the top of the container

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

textView.textContainerInset = .zero

Both Lines are needed to completely remove the margin/padding.

需要两行才能完全删除边距/填充。

回答by Michael

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

此解决方法是在 2009 年发布 IOS 3.0 时编写的。它不再适用。

I ran into the exact same problem, in the end I had to wind up using

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

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

where nameField is a UITextView. The font I happened to be using was Helvetica 16 point. Its only a custom solution for the particular field size I was drawing. This makes the left offset flush with the left side, and the top offset where I want it for the box its draw in.

其中 nameField 是一个UITextView. 我碰巧使用的字体是 Helvetica 16 点。它只是针对我正在绘制的特定字段大小的自定义解决方案。这使得左侧偏移与左侧齐平,而顶部偏移则是我希望它用于绘制的框。

In addition, this only seems to apply to UITextViewswhere you are using the default aligment, ie.

此外,这似乎仅适用于UITextViews您使用默认对齐方式的地方,即。

nameField.textAlignment = NSTextAlignmentLeft;

Align to the right for example and the UIEdgeInsetsMakeseems to have no impact on the right edge at all.

例如,向右对齐,UIEdgeInsetsMake似乎对右边缘根本没有影响。

At very least, using the .contentInset property allows you to place your fields with the "correct" positions, and accommodate the deviations without offsetting your UITextViews.

至少,使用 .contentInset 属性可以让您将字段放置在“正确”的位置,并在不偏移您的UITextViews.

回答by azdev

Building off some of the good answers already given, here is a purely Storyboard / Interface Builder-based solution that works in iOS 7.0+

基于已经给出的一些好的答案,这里是一个纯粹的基于 Storyboard/Interface Builder 的解决方案,适用于 iOS 7.0+

Set the UITextView's User Defined Runtime Attributesfor the following keys:

为以下键设置 UITextView 的用户定义的运行时属性

textContainer.lineFragmentPadding
textContainerInset

Interface Builder

界面生成器

回答by Engin Kurutepe

On iOS 5 UIEdgeInsetsMake(-8,-8,-8,-8);seems to work great.

在 iOS 5 上UIEdgeInsetsMake(-8,-8,-8,-8);似乎工作得很好。

回答by ldoogy

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

我绝对会避免任何涉及硬编码值的答案,因为实际边距可能会随着用户字体大小设置等而变化。

Here is @user1687195's answer, written without modifying the textContainer.lineFragmentPadding(because the docsstate this is not the intended usage).

这是@user1687195 的答案,没有修改textContainer.lineFragmentPadding(因为文档说明这不是预期的用法)。

This works great for iOS 7 and later.

这适用于 iOS 7 及更高版本。

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

This is effectively the same outcome, just a bit cleaner in that it doesn't misuse the lineFragmentPadding property.

这实际上是相同的结果,只是更清晰一点,因为它不会滥用 lineFragmentPadding 属性。

回答by Uladzimir

Storyboard or Interface Builder solution using User Defined Runtime Attributes:

使用用户定义的运行时属性的Storyboard 或 Interface Builder 解决方案:

Screenshots are of iOS 7.1 & iOS 6.1 with contentInset = {{-10, -5}, {0, 0}}.

屏幕截图来自 iOS 7.1 和 iOS 6.1,带有contentInset = {{-10, -5}, {0, 0}}.

User Defined Runtime Attributes

用户定义的运行时属性

output

输出

回答by mikeho

All these answers address the title question, but I wanted to propose some solutions for the problems presented in the body of the OP's question.

所有这些答案都解决了标题问题,但我想为 OP 问题正文中提出的问题提出一些解决方案。

Size of Text Content

文本内容的大小

A quick way to calculate the size of the text inside the UITextViewis to use the NSLayoutManager:

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

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

This gives the total scrollable content, which may be bigger than the UITextView's frame. I found this to be much more accurate than textView.contentSizesince it actually calculates how much space the text takes up. For example, given an empty UITextView:

这给出了总可滚动内容,它可能大于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)

Line Height

线高

UIFonthas a property that quickly allows you to get the line height for the given font. So you can quickly find the line height of the text in your UITextViewwith:

UIFont有一个属性可以让你快速获取给定字体的行高。因此,您可以使用以下命令快速找到文本的行高UITextView

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

Calculating Visible Text Size

计算可见文本大小

Determining the amount of text that is actually visible is important for handling a "paging" effect. UITextViewhas a property called textContainerInsetwhich actually is a margin between the actual UITextView.frameand the text itself. To calculate the real height of the visible frame you can perform the following calculations:

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

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

Determining Paging Size

确定分页大小

Lastly, now that you have the visible text size and the content, you can quickly determine what your offsets should be by subtracting the textHeightfrom the textSize:

最后,现在你有可见的文字大小和内容,您可以快速确定您的偏移量应减去什么textHeight来自textSize

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

Using all of these methods, I didn't touch my insets and I was able to go to the caret or wherever in the text that I want.

使用所有这些方法,我没有触及我的插图,我能够转到插入符号或我想要的文本中的任何位置。

回答by Himanshu padia

you can use textContainerInsetproperty of UITextView:

您可以使用以下textContainerInset属性UITextView

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

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

(top, left, bottom, right)

(上、左、下、右)

回答by Anson Yao

For iOS 10, the following line works for the top and bottom padding removing.

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

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