it-swarm.com.de

Text vertikal zentrieren in einer UITextView

Ich möchte den Text vertikal in einem großen UITextView, der den gesamten Bildschirm ausfüllt - zentrieren. Wenn nur wenig Text vorhanden ist, sagen wir ein paar Wörter, wird er nach Höhe zentriert. Es geht nicht darum, den Text zu zentrieren (eine Eigenschaft, die in IB zu finden ist), sondern den Text vertikal rechts in der Mitte von UITextView wenn der Text kurz ist, also Keine leeren Bereiche in UITextView. Kann das gemacht werden? Danke im Voraus!

57

Fügen Sie zunächst einen Beobachter für den Schlüsselwert contentSize der Variablen UITextView hinzu, wenn die Ansicht geladen ist:

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

Fügen Sie dann diese Methode hinzu, um die contentOffset bei jeder Änderung des contentSize-Werts anzupassen:

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

Da UIKit nicht KVO-konform ist , habe ich mich entschlossen, dies als Unterklasse von UITextView zu implementieren, die bei jeder Änderung der contentSize aktualisiert wird. 

Es ist eine leicht modifizierte Version von der Antwort von Carlos , die die contentInset anstelle der contentOffset setzt. Abgesehen davon, dass mit iOS 9 kompatibel ist , scheint es auch auf iOS 8.4 weniger fehlerhaft zu sein.

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

Wenn Sie KVO nicht verwenden möchten, können Sie den Offset auch manuell anpassen, indem Sie diesen Code in eine Funktion wie die folgende exportieren:

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

und es anrufen 

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

und jedes Mal, wenn Sie den Text im Code bearbeiten. Vergessen Sie nicht, den Controller als Delegierten festzulegen

Swift 3 Version:  

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

Für iOS 9.0.2. Wir müssen stattdessen das contentInset festlegen. Wenn wir das contentOffset als KVO verwenden, setzt es iOS 9.0.2 im letzten Moment auf 0 und überschreibt die Änderungen an 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];
}

Ich habe 0,0 und 0 für den linken, unteren und rechten Rand eingesetzt. Stellen Sie sicher, dass Sie diese auch für Ihren Anwendungsfall berechnen. 

20
s.ka

Hier ist eine Erweiterung von UITextView, die den Inhalt vertikal zentriert:

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
    }

}
6

Swift 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
user5195185
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

Sie können es nur mit Einschränkungen direkt einrichten:

Ich habe drei Einschränkungen hinzugefügt, um Text vertikal und horizontal in Einschränkungen wie folgt auszurichten:

 enter image description here

  1. Stellen Sie die Höhe auf 0 und fügen Sie Einschränkungen hinzu, die größer als sind
  2. Hinzufügen vertikaler Ausrichtung zu übergeordneten Einschränkungen
  3. Horizontale Ausrichtung zu übergeordneten Abhängigkeiten hinzufügen

 enter image description here

5
KOTIOS

Ich habe eine Textansicht, die ich mit Autolayout verwende und lineFragmentPadding und textContainerInset auf null setzt. Keine der oben genannten Lösungen funktionierte in meiner Situation. Dies funktioniert jedoch für mich. Mit iOS 9 getestet

@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

Ich habe auch dieses Problem und ich habe es mit einer UITableViewCell mit UITextView gelöst. Ich habe eine Methode in einer benutzerdefinierten UITableViewCell-Unterklasse erstellt, Eigenschaft 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 };

Und rufen Sie diese Methode in Methoden auf:

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

Diese Lösung hat für mich ohne Probleme funktioniert, Sie können es ausprobieren.

4
Miro Durkovic

Ich habe gerade eine benutzerdefinierte vertikal zentrierte Textansicht in Swift 3 erstellt:

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

ref: http://geek-is-stupid.github.io/blog/2017/03/14/how-to-center-text-vertically-in-a-uitextview/

3
Tai Le

Fügen Sie Carlos Antwort hinzu, nur für den Fall, dass Sie Text in TV haben, der größer als die TV-Größe ist.

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

zu diesem:

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

Auto-Layout-Lösung:

  1. Erstellen Sie eine UIView, die als Container für die UITextView fungiert.
  2. Fügen Sie die folgenden Einschränkungen hinzu:
    • TextView: Führende Leerzeichen an: Container ausrichten
    • TextView: Nachlaufendes Leerzeichen an: Container ausrichten
    • Textansicht: Zentriert Y an: Container
    • TextView: Gleiche Höhe zu: Container, Beziehung: ≤
1
Etan

Ich habe dieses Problem behoben, indem ich eine Erweiterung für die vertikale Mittenhöhe erstellt habe.

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

Sie können den folgenden Code ausprobieren, es ist kein Beobachter erforderlich. Der Beobachter gibt manchmal eine Fehlermeldung aus, wenn view deallocates ..__ Sie können diesen Code in viewDidLoad, viewWillAppear oder viewDidAppear an einer beliebigen Stelle aufbewahren. 

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};
    });
});
0
Kiran Jasvanee

Ich habe es so gemacht: Zuerst habe ich den UITextView in eine UIView eingebettet (dies sollte auch für Mac OS funktionieren). Dann habe ich alle vier Seiten des externen UIView an den Seiten des Containers fixiert und ihm eine Form und Größe gegeben, die der des UITextView ähnelt oder dieser entspricht. Somit hatte ich einen richtigen Container für die UITextView. Dann habe ich den linken und rechten Rand des UITextView an den Seiten des UIView fixiert und dem UITextView eine Höhe zugewiesen. Schließlich habe ich die UITextView vertikal in der UIView zentriert. Bingo :) Die UITextView ist jetzt in der UIView vertikal zentriert, daher ist der Text in der UITextView auch vertikal zentriert.

0
user2626974