web-dev-qa-db-ja.com

UITextViewでマージン/パディングをなくすには?

私のiOSアプリケーションにはUITextViewがあります。これは大量のテキストを表示します。

次に、UITextViewのoffset marginパラメータを使用してこのテキストをページングしています。

私の問題は、UITextViewのパディングが私の計算を混乱させていることです。それは私が使うフォントサイズと書体によって異なるように思われるからです。

したがって、私は質問をします:UITextViewの内容を囲むパディングを削除することは可能ですか?

あなたの回答をお待ちしています!

442
sniurkst

2019年の最新

これはiOSの最も厄介なバグの1つです。

以下のクラスUITextViewFixedは通常妥当な解決策です。

これがクラスです:

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

インスペクタでscrollEnabledをオフにすることを忘れないでください。

  1. 解決策はストーリーボードで正しく機能します

  2. このソリューションは実行時に適切に機能します

それで、終わりです。

一般的に、ほとんどの場合に必要なのはこれだけです

あなたがその場でテキストビューの高さを変えているとしても、これは通常あなたが必要とするすべてをします。

(その場で高さを変更する一般的な例は、ユーザーの入力に応じて変更することです。)

これはAppleからの壊れたUITextViewです...

screenshot of IB with UITextView

これがUITextViewFixedです。

screenshot of IB with UITextViewFixed

もちろんあなたがしなければならないことに注意してください

インスペクタでscrollEnabledをオフにします。

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

280
Fattie

IOS 7.0の場合、私はcontentInsetトリックがもはや機能しないことを発見しました。これは私がiOS 7でマージン/パディングを取り除くために使用したコードです。

これにより、テキストの左端がコンテナの左端に移​​動します。

textView.textContainer.lineFragmentPadding = 0

これにより、テキストの上部がコンテナの上部と揃うようになります。

textView.textContainerInset = .zero

両方の行は、マージン/パディングを完全に削除するために必要です。

758
user1687195

この回避策は、IOS 3.0がリリースされた2009年に書かれました。現在は適用されていません。

私は使用して巻き上げなければならなかった結局、私はまったく同じ問題に遭遇しました

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

nameFieldはUITextViewです。たまたま使っていたフォントはHelvetica 16ポイントでした。それは私が描いていた特定のフィールドサイズに対する唯一のカスタムソリューションです。これにより、左側のオフセットは左側と同じ高さになり、上部のオフセットはボックスの描画位置になります。

さらに、これはデフォルトのアライメントを使っているUITextViewsにのみ当てはまるようです。

nameField.textAlignment = NSTextAlignmentLeft;

たとえば、右に揃えると、UIEdgeInsetsMakeは右のEdgeにまったく影響を与えないようです。

少なくとも、.contentInsetプロパティを使用すると、フィールドを「正しい」位置に配置し、UITextViewsをオフセットせずに偏差に対応できます。

251
Michael

すでに与えられたいくつかの良い答えを基にして、これは純粋にInterface Builderベースのソリューションで、ユーザー定義のランタイム属性を利用し、iOS 7.0以降で動作します。

enter image description here

70
azdev

IOS 5ではUIEdgeInsetsMake(-8,-8,-8,-8);はうまく動作するようです。

45
Engin Kurutepe

実際のマージンはユーザーのフォントサイズの設定などによって変わる可能性があるので、ハードコーディングされた値に関する回答は絶対に避けてください

これはtextContainer.lineFragmentPaddingを変更せずに書かれた@ user1687195の答えです( docs と記述されているのでこれは意図した使用法ではありません)。

これはiOS 7以降ではうまく機能します。

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

これは事実上同じ結果で、lineFragmentPaddingプロパティを悪用しないという点でほんの少しきれいです。

39
ldoogy

ユーザー定義のランタイム属性を使用したスト​​ーリーボードまたはInterface Builderソリューション。 更新。 contentInset = {{-10、-5}、{0、0}}のiOS7.1とiOS6.1のスクリーンショットを追加しました enter image description hereenter image description here

18
Uladzimir

これらすべての答えはタイトルの質問に対処しますが、私は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

これらすべての方法を使用して、私は私のインセットに触れず、そして私はキャレットにまたは私が望むテキストのどこにでも行くことができました。

15
mikeho

textContainerInsetUITextViewプロパティを使用できます。

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

(上、左、下、右)

11
Himanshu padia

IOS 10の場合、上下のパディング除去に次の行が働きます。

captionTextView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
9
Anson Yao

これは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をオフにするのを忘れないでください。
この解決方法はストーリーボードでも実行時でも正しく機能します。

これで終わりです、これで本当にできました!

6
Fab1n

最新のスイフト:

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

Swift 4、Xcode 9の場合

次の関数を使用すると、UITextViewのテキストの余白/余白を変更できます。

public func UIEdgeInsetsMake(_上:CGFloat、_左:CGFloat、_下:CGFloat、_右:CGFloat) - > UIEdgeInsets

だからこの場合です

 self.textView?.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)
3
Shan Ye

これはあなたのアプリのすべてのテキストビューから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);
   }
}
2
Cal S

差し込みソリューションを実行しても、右側と下部にまだパディングがありました。テキストの配置も問題を引き起こしていました。私が見つけた唯一の確実な発射方法は、境界に切り取られた別のビューの中にテキストビューを置くことでした。

2
rp90

私(iOS 11およびXcode 9.4.1)にとって魔法のように機能したのは、textView.fontプロパティをUIFont.preferred(forTextStyle:UIFontTextStyle)スタイルに設定すること、そして@Fattieが述べた最初の答えでした。しかし、@ Fattieの答えは、textView.fontプロパティを設定するまではうまくいきませんでした。それ以外の場合、UITextViewは不規則に振る舞い続けます。

0
Nikhil Pandey

最新のSwiftバージョンを探している人なら、以下のコードでXcode 10.2Swift 4.2でうまく動作しています。

yourTextView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
0
Bhavin_m