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
How to lose margin/padding in UITextView?
提问by sniurkst
I have a UITextView
in 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 UITextView
is 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, UITextViewFixed
is 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 !
The solution works properly in storyboard
The solution works properly at runtime
该解决方案在故事板中正常工作
该解决方案在运行时正常工作
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, UITextViewFixed
usually 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 ......
Here is UITextViewFixed
:
这是UITextViewFixed
:
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 = 0
in UITextViewFixed
.
就.lineFragmentPadding = 0
在UITextViewFixed
.
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 UITextView
is 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".
太好了,但是如果根本没有文字,那么不幸的是,您获得的高度与只有一行文字的高度相同!文本视图永远不会“消失”。
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
}
(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 UITextViews
where you are using the default aligment, ie.
此外,这似乎仅适用于UITextViews
您使用默认对齐方式的地方,即。
nameField.textAlignment = NSTextAlignmentLeft;
Align to the right for example and the UIEdgeInsetsMake
seems 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
回答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}}
.
回答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 UITextView
is 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.contentSize
since 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
线高
UIFont
has 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 UITextView
with:
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. UITextView
has a property called textContainerInset
which actually is a margin between the actual UITextView.frame
and 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 textHeight
from 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 textContainerInset
property 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)