Nice programing

UITextView에서 세로로 텍스트 가운데 맞춤

nicepro 2020. 11. 22. 20:31
반응형

UITextView에서 세로로 텍스트 가운데 맞춤


전체 화면을 채우는 큰 내부에 텍스트를 세로 로 가운데에 배치하여 텍스트 UITextView가 거의 없을 때 (예 : 몇 단어) 높이를 기준으로 가운데에 배치합니다. 텍스트 (IB에서 찾을 수있는 속성)를 중앙 에 배치하는 것에 대한 질문이 아니라 텍스트가 짧은 경우 텍스트를 세로로 오른쪽에 배치 하여 . 할 수 있습니까? 미리 감사드립니다!UITextView UITextView


먼저 뷰가로드 될 때의 contentSize키 값에 대한 관찰자를 추가합니다 UITextView.

- (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};
}

UIKit은 KVO와 호환되지 않기 때문에 변경 UITextView될 때마다 업데이트 되는 하위 클래스로 구현하기로 결정했습니다 contentSize.

그것은 약간 수정 된 버전의 카를로스의 대답 세트 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)
        }
    }
}

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)
}

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을 사용했습니다. 사용 사례에 대해서도 계산하십시오.


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
    }

}

제약 조건만으로 직접 설정할 수 있습니다.

다음과 같이 제약 조건에서 텍스트를 세로 및 가로로 정렬하기 위해 추가 한 3 개의 제약 조건이 있습니다.

여기에 이미지 설명 입력

  1. 높이를 0으로 만들고 다음보다 큰 제약 조건을 추가합니다.
  2. 상위 제약 조건에 수직 정렬 추가
  3. 부모 제약 조건에 수평 정렬 추가

여기에 이미지 설명 입력


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)
}

autolayout과 함께 사용하고 lineFragmentPaddingand textContainerInset를 0 으로 설정하는 textview가 있습니다. 위의 솔루션 중 어느 것도 내 상황에서 작동하지 않았습니다. 그러나 이것은 나를 위해 작동합니다. 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

스위프트 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)

    }

나는 또한이 문제를 가지고 UITableViewCell있으며 UITextView. 사용자 지정 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

이 솔루션은 문제없이 저에게 효과적이었습니다. 시도해 볼 수 있습니다.


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


Carlos 답변에 추가하십시오. TV의 텍스트가 TV 크기보다 클 경우 텍스트를 최근에 올릴 필요가 없으므로 다음 코드를 변경하십시오.

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

이에:

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

자동 레이아웃 솔루션 :

  1. UITextView의 컨테이너 역할을하는 UIView를 만듭니다.
  2. 다음 제약 조건을 추가합니다.
    • TextView : 선행 공백 정렬 : 컨테이너
    • TextView : 후행 공백 정렬 : 컨테이너
    • TextView : 중앙 Y 정렬 : 컨테이너
    • TextView: Equal Height to: Container, Relation: ≤

You can try below code, no observer mandatorily required. observer throws error sometimes when view deallocates. You can keep this code in viewDidLoad, viewWillAppear or in viewDidAppear anywhere.

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};
    });
});

I did it like this: first of all, I embedded the UITextView in an UIView (this should work for mac OS too). Then I pinned all four sides of the external UIView to the sides of its container, giving it a shape and size similar or equal to that of the UITextView. Thus I had a proper container for the UITextView. Then I pinned the left and right borders of the UITextView to the sides of the UIView, and gave the UITextView a height. Finally, I centered the UITextView vertically in the UIView. Bingo :) now the UITextView is vertically centered in the UIView, hence text inside the UITextView is vertically centered too.


I fixed this problem by creating extension to center height vertically.

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

UITextView+VerticalAlignment.h

//  UITextView+VerticalAlignment.h
//  (c) The Internet 2015
#import <UIKit/UIKit.h>

@interface UITextView (VerticalAlignment)

- (void)alignToVerticalCenter;
- (void)disableAlignment;

@end

UITextView+VerticalAlignment.m

#import "UITextView+VerticalAlignment.h"

@implementation UITextView (VerticalAlignment)

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

- (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};
}

- (void)disableAlignment {
    [self removeObserver:self forKeyPath:@"contentSize"];
}
@end

Solution for iOS10 in RubyMotion:

class VerticallyCenteredTextView < UITextView

    def init
        super
    end

    def layoutSubviews
        self.recenter
    end

    def recenter
        contentSize = self.sizeThatFits(CGSizeMake(self.bounds.size.width, Float::MAX))
        topCorrection = (self.bounds.size.height - contentSize.height * self.zoomScale) / 2.0;
        topCorrection = 0 if topCorrection < 0
        self.contentInset = UIEdgeInsetsMake(topCorrection,  0, 0, 0)
    end

end

참고 URL : https://stackoverflow.com/questions/12591192/center-text-vertically-in-a-uitextview

반응형