私のiOSアプリケーションにはUITextView
があります。これは大量のテキストを表示します。
次に、UITextView
のoffset marginパラメータを使用してこのテキストをページングしています。
私の問題は、UITextView
のパディングが私の計算を混乱させていることです。それは私が使うフォントサイズと書体によって異なるように思われるからです。
したがって、私は質問をします:UITextView
の内容を囲むパディングを削除することは可能ですか?
あなたの回答をお待ちしています!
これはiOSの最も厄介なバグの1つです。
以下のクラスUITextViewFixed
は通常妥当な解決策です。
これがクラスです:
@IBDesignable class UITextViewFixed: UITextView {
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
func setup() {
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
}
}
インスペクタでscrollEnabledをオフにすることを忘れないでください。
解決策はストーリーボードで正しく機能します
このソリューションは実行時に適切に機能します
一般的に、ほとんどの場合に必要なのはこれだけです。
あなたがその場でテキストビューの高さを変えているとしても、これは通常あなたが必要とするすべてをします。
(その場で高さを変更する一般的な例は、ユーザーの入力に応じて変更することです。)
これはAppleからの壊れたUITextViewです...
これがUITextViewFixed
です。
もちろんあなたがしなければならないことに注意してください
ScrollEnabledをオフにすることを忘れないでください。 :)
(1)いくつかの珍しいケースでは - 例えば、動的に変化する高さを持つ柔軟なセルの高さのテーブルビューの場合 - Appleは奇妙なことをします:下いや、本当に!これはiOSで最も不愉快なことの1つでなければならないでしょう。
これは、通常その狂気を解消するのに役立つ「簡単な修正」です。
...
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)時々、さらに別の微妙なAppleの混乱を修正するために、これを追加しなければなりません:
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
super.setContentOffset(contentOffset, animated: false)
}
(3)間違いなく、私たちは追加するべきです:
contentInset = UIEdgeInsets.zero
UITextViewFixed
の.lineFragmentPadding = 0
の直後。
しかし...信じられないかもしれませんが...現在のiOSではは動作しません! (2019年にチェックされます。)将来その行を追加する必要があるかもしれません。
IOSでUITextView
が壊れているという事実は、すべてのモバイルコンピューティングで最も奇妙なことの1つです。この質問の10周年、そしてそれはまだ決まっていません!
最後に、これはテキストフィールドのためのやや似たようなヒントです: https://stackoverflow.com/a/43099816/294884
IOS 7.0の場合、私はcontentInsetトリックがもはや機能しないことを発見しました。これは私がiOS 7でマージン/パディングを取り除くために使用したコードです。
これにより、テキストの左端がコンテナの左端に移動します。
textView.textContainer.lineFragmentPadding = 0
これにより、テキストの上部がコンテナの上部と揃うようになります。
textView.textContainerInset = .zero
両方の行は、マージン/パディングを完全に削除するために必要です。
この回避策は、IOS 3.0がリリースされた2009年に書かれました。現在は適用されていません。
私は使用して巻き上げなければならなかった結局、私はまったく同じ問題に遭遇しました
nameField.contentInset = UIEdgeInsetsMake(-4,-8,0,0);
nameFieldはUITextView
です。たまたま使っていたフォントはHelvetica 16ポイントでした。それは私が描いていた特定のフィールドサイズに対する唯一のカスタムソリューションです。これにより、左側のオフセットは左側と同じ高さになり、上部のオフセットはボックスの描画位置になります。
さらに、これはデフォルトのアライメントを使っているUITextViews
にのみ当てはまるようです。
nameField.textAlignment = NSTextAlignmentLeft;
たとえば、右に揃えると、UIEdgeInsetsMake
は右のEdgeにまったく影響を与えないようです。
少なくとも、.contentInsetプロパティを使用すると、フィールドを「正しい」位置に配置し、UITextViews
をオフセットせずに偏差に対応できます。
すでに与えられたいくつかの良い答えを基にして、これは純粋にInterface Builderベースのソリューションで、ユーザー定義のランタイム属性を利用し、iOS 7.0以降で動作します。
IOS 5ではUIEdgeInsetsMake(-8,-8,-8,-8);
はうまく動作するようです。
実際のマージンはユーザーのフォントサイズの設定などによって変わる可能性があるので、ハードコーディングされた値に関する回答は絶対に避けてください
これはtextContainer.lineFragmentPadding
を変更せずに書かれた@ user1687195の答えです( docs と記述されているのでこれは意図した使用法ではありません)。
これはiOS 7以降ではうまく機能します。
self.textView.textContainerInset = UIEdgeInsetsMake(
0,
-self.textView.textContainer.lineFragmentPadding,
0,
-self.textView.textContainer.lineFragmentPadding);
これは事実上同じ結果で、lineFragmentPaddingプロパティを悪用しないという点でほんの少しきれいです。
ユーザー定義のランタイム属性を使用したストーリーボードまたはInterface Builderソリューション。 更新。 contentInset = {{-10、-5}、{0、0}}のiOS7.1とiOS6.1のスクリーンショットを追加しました
これらすべての答えはタイトルの質問に対処しますが、私は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;
最後に、表示されるテキストのサイズと内容が決まったので、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
これらすべての方法を使用して、私は私のインセットに触れず、そして私はキャレットにまたは私が望むテキストのどこにでも行くことができました。
textContainerInset
のUITextView
プロパティを使用できます。
textView.textContainerInset = UIEdgeInsetsMake(10、10、10、10);
(上、左、下、右)
IOS 10の場合、上下のパディング除去に次の行が働きます。
captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
これはFattieの非常に役に立つ答えの更新版です。それは私がiOS 10と11(そしておそらくそれより下のものにも)上で働く完璧なレイアウトを得るのを助けた2つの非常に重要な行を追加します。
d
@IBDesignable class UITextViewFixed: UITextView {
override func layoutSubviews() {
super.layoutSubviews()
setup()
}
func setup() {
translatesAutoresizingMaskIntoConstraints = true
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 0
translatesAutoresizingMaskIntoConstraints = false
}
}
重要な行は2つのtranslatesAutoresizingMaskIntoConstraints = <true/false>
ステートメントです!
これは驚くほど--- すべてのマージンを削除する私のすべての状況で!
textView
は最初の応答者ではありませんが、受け入れられた回答に記載されているsizeThatFits
メソッドを使用しても解決できない奇妙な下余白がある可能性があります。
textViewを突然タップすると、奇妙な下の余白がなくなり、すべてが本来の状態になりましたが、textViewがfirstResponder
を取得した直後に限ります。
だから私は ここではSO を読み、translatesAutoresizingMaskIntoConstraints
を有効にしたり無効にしたりすることは、呼び出しの間に手動でフレーム/境界を設定するときに役立つことを示しています。
幸い、これはフレーム設定だけでなく、2つのtranslatesAutoresizingMaskIntoConstraints
呼び出しの間に挟まれた2行のsetup()
でも機能します。
例えば、これは非常に役立つビューのフレームを計算するときsystemLayoutSizeFitting
に対してUIView
を使うです。正しいサイズを返します(以前はそうではありませんでした)。
最初に述べたように、
InspectorでscrollEnabledをオフにするのを忘れないでください。
この解決方法はストーリーボードでも実行時でも正しく機能します。
これで終わりです、これで本当にできました!
最新のスイフト:
self.textView.textContainerInset = .init(top: -2, left: 0, bottom: 0, right: 0)
self.textView.textContainer.lineFragmentPadding = 0
Swift 4、Xcode 9の場合
次の関数を使用すると、UITextViewのテキストの余白/余白を変更できます。
public func UIEdgeInsetsMake(_上:CGFloat、_左:CGFloat、_下:CGFloat、_右:CGFloat) - > UIEdgeInsets
だからこの場合です
self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
これはあなたのアプリのすべてのテキストビューから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);
}
}
差し込みソリューションを実行しても、右側と下部にまだパディングがありました。テキストの配置も問題を引き起こしていました。私が見つけた唯一の確実な発射方法は、境界に切り取られた別のビューの中にテキストビューを置くことでした。
私(iOS 11およびXcode 9.4.1)にとって魔法のように機能したのは、textView.fontプロパティをUIFont.preferred(forTextStyle:UIFontTextStyle)
スタイルに設定すること、そして@Fattieが述べた最初の答えでした。しかし、@ Fattieの答えは、textView.fontプロパティを設定するまではうまくいきませんでした。それ以外の場合、UITextViewは不規則に振る舞い続けます。
最新のSwiftバージョンを探している人なら、以下のコードでXcode 10.2とSwift 4.2でうまく動作しています。
yourTextView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)