web-dev-qa-db-ja.com

UITextViewでテキストを垂直方向に中央揃え

テキストを中央揃えにしたい垂直方向画面全体を埋める大きなUITextViewの内側に-少しのテキスト、たとえば2、3個の単語がある場合、高さによって中央揃えにします。テキスト(IBにあるプロパティ)の中央揃えに関する問題ではなく、テキストの配置についての質問ではありません垂直UITextViewの真ん中ifテキストは短いため、UITextViewには空白の領域はありません。これはできますか?前もって感謝します!

62

ビューがロードされたときに、最初にcontentSizeUITextViewキー値のオブザーバーを追加します。

- (void) viewDidLoad {
     [textField addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
     [super viewDidLoad];
}

次に、このメソッドを追加して、contentOffset値が変更されるたびにcontentSizeを調整します。

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
     UITextView *tv = object;
     CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
     topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
     tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
61
CSolanaM

IKitはKVOに準拠していない であるため、UITextViewが変更されるたびに更新するcontentSizeのサブクラスとしてこれを実装することにしました。

これは、 Carlosの答え のわずかに変更されたバージョンで、contentInsetの代わりにcontentOffsetを設定します。 iOS 9と互換性がある に加えて、iOS 8.4ではバグが少ないようです。

class VerticallyCenteredTextView: UITextView {
    override var contentSize: CGSize {
        didSet {
            var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
            topCorrection = max(0, topCorrection)
            contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
        }
    }
}
47
Senseful

KVOを使用したくない場合は、このコードを次のような関数にエクスポートしてオフセットを手動で調整することもできます。

-(void)adjustContentSize:(UITextView*)tv{
    CGFloat deadSpace = ([tv bounds].size.height - [tv contentSize].height);
    CGFloat inset = MAX(0, deadSpace/2.0);
    tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right);
}  

そしてそれを呼び出す

-(void)textViewDidChange:(UITextView *)textView{
    [self adjustContentSize:textView];
}

また、コード内のテキストを編集するたびに。コントローラーをデリゲートとして設定することを忘れないでください

Swift 3バージョン:

func adjustContentSize(tv: UITextView){
    let deadSpace = tv.bounds.size.height - tv.contentSize.height
    let inset = max(0, deadSpace/2.0)
    tv.contentInset = UIEdgeInsetsMake(inset, tv.contentInset.left, inset, tv.contentInset.right)
}

func textViewDidChange(_ textView: UITextView) {
    self.adjustContentSize(tv: textView)
}
25
Beninho85

IOS 9.0.2の場合。代わりにcontentInsetを設定する必要があります。 contentOffsetをKVOにすると、iOS 9.0.2は最後にそれを0に設定し、contentOffsetへの変更を上書きします。

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    UITextView *tv = object;
    CGFloat topCorrect = ([tv bounds].size.height - [tv     contentSize].height * [tv zoomScale])/2.0;
    topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
    [tv setContentInset:UIEdgeInsetsMake(topCorrect,0,0,0)];
}

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:NO];
    [questionTextView addObserver:self forKeyPath:@"contentSize" options:(NSKeyValueObservingOptionNew) context:NULL];
}

左、下、右の端のインセットにそれぞれ0、0、0を使用しました。ユースケースに合わせてこれらも計算してください。

20
s.ka

コンテンツを垂直方向に中央揃えするUITextView拡張機能は次のとおりです。

extension UITextView {

    func centerVertically() {
        let fittingSize = CGSize(width: bounds.width, height: CGFloat.max)
        let size = sizeThatFits(fittingSize)
        let topOffset = (bounds.size.height - size.height * zoomScale) / 2
        let positiveTopOffset = max(0, topOffset)
        contentOffset.y = -positiveTopOffset
    }

}
8

スウィフト3:

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        textField.frame = self.view.bounds

        var topCorrect : CGFloat = (self.view.frame.height / 2) - (textField.contentSize.height / 2)
        topCorrect = topCorrect < 0.0 ? 0.0 : topCorrect
        textField.contentInset = UIEdgeInsetsMake(topCorrect,0,0,0)

    }
5
arnaldito100
func alignTextVerticalInTextView(textView :UITextView) {

    let size = textView.sizeThatFits(CGSizeMake(CGRectGetWidth(textView.bounds), CGFloat(MAXFLOAT)))

    var topoffset = (textView.bounds.size.height - size.height * textView.zoomScale) / 2.0
    topoffset = topoffset < 0.0 ? 0.0 : topoffset

    textView.contentOffset = CGPointMake(0, -topoffset)
}
5
Ievgen

制約のみで直接設定できます:

以下のように、制約内でテキストを垂直および水平に配置するために追加された3つの制約があります。

enter image description here

  1. 高さを0にし、より大きい制約を追加します
  2. 親コンストレイントに垂直方向に配置する
  3. 親コンストレイントに水平方向に整列を追加します

enter image description here

5
KOTIOS

AutolayoutとlineFragmentPaddingtextContainerInsetをゼロに設定して使用しているテキストビューがあります。上記の解決策はいずれも私の状況では機能しませんでした。しかし、これは私には有効です。 iOS 9でテスト済み

@interface VerticallyCenteredTextView : UITextView
@end

@implementation VerticallyCenteredTextView

-(void)layoutSubviews{
    [self recenter];
}

-(void)recenter{
    // using self.contentSize doesn't work correctly, have to calculate content size
    CGSize contentSize = [self sizeThatFits:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)];
    CGFloat topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0;
    self.contentOffset = CGPointMake(0, -topCorrection);
}

@end
5
user1687195

この問題もあり、UITableViewCellUITextViewで解決しました。カスタムUITableViewCellサブクラス、プロパティstatusTextViewでメソッドを作成しました:

- (void)centerTextInTextView
{
    CGFloat topCorrect = ([self.statusTextView bounds].size.height - [self.statusTextView contentSize].height * [self.statusTextView zoomScale])/2.0;
    topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
    self.statusTextView.contentOffset = (CGPoint){ .x = 0, .y = -topCorrect };

そして、メソッドでこのメソッドを呼び出します:

- (void)textViewDidBeginEditing:(UITextView *)textView
- (void)textViewDidEndEditing:(UITextView *)textView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

このソリューションは問題なく機能しました。試してみてください。

4
Miro Durkovic

Swift 3:

class VerticallyCenteredTextView: UITextView {
    override var contentSize: CGSize {
        didSet {
            var topCorrection = (bounds.size.height - contentSize.height * zoomScale) / 2.0
            topCorrection = max(0, topCorrection)
            contentInset = UIEdgeInsets(top: topCorrection, left: 0, bottom: 0, right: 0)
        }
    }
}

参照: https://geek-is-stupid.github.io/2017-05-15-how-to-center-text-vertically-in-a-uitextview/

3
Tai Le

Carlosの回答に追加してください。テレビのテキストがテレビのサイズよりも大きい場合は、テキストを再センタリングする必要がないので、このコードを変更します。

tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};

これに:

if ([tv contentSize].height < [tv bounds].size.height) {
     tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
}
2
user3777977

自動レイアウトソリューション:

  1. UITextViewのコンテナとして機能するUIViewを作成します。
  2. 次の制約を追加します。
    • TextView:先頭のスペースをコンテナに揃えます:コンテナ
    • TextView:末尾のスペースをコンテナに揃えます:コンテナ
    • TextView:中心Yを整列:コンテナ
    • TextView:等しい高さ:コンテナ、関係:≤
2
Etan

以下のコードを試すことができますが、オブザーバーは必須ではありません。ビューの割り当てが解除されると、オブザーバーがエラーをスローすることがあります。このコードは、viewDidLoad、viewWillAppear、またはviewDidAppearのどこにでも保存できます。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_async(dispatch_get_main_queue(), ^(void) {
        UITextView *tv = txtviewDesc;
        CGFloat topCorrect = ([tv bounds].size.height - [tv contentSize].height * [tv zoomScale])/2.0;
        topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect );
        tv.contentOffset = (CGPoint){.x = 0, .y = -topCorrect};
    });
});
1
Kiran Jasvanee

この問題を修正するために、中心の高さを垂直方向に延長しました。

Swift 5:

extension UITextView {
    func centerContentVertically() {
        let fitSize = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
        let size = sizeThatFits(fitSize)
        let heightOffset = (bounds.size.height - size.height * zoomScale) / 2
        let positiveTopOffset = max(0, heightOffset)
        contentOffset.y = -positiveTopOffset
    }
}
0
user1039695

私はこのようにしました。まず、UIViewにUITextViewを埋め込みました(これはMac OSでも機能するはずです)。次に、外部UIViewの4つの側面すべてをコンテナーの側面に固定し、UITextViewの形状およびサイズと同等または等しい形状とサイズを与えました。したがって、UITextViewの適切なコンテナがありました。次に、UITextViewの左右の境界線をUIViewの側面に固定し、UITextViewに高さを与えました。最後に、UITextViewをUIViewの垂直方向の中央に配置しました。 Bingo :)これで、UITextViewはUIViewの垂直方向の中央に配置されるため、UITextView内のテキストも垂直方向の中央に配置されます。

0
user2626974