it-swarm.com.de

Wie kann ich eine Größe von UITextView unter iOS 7 anpassen?

Ich habe die akzeptierte Antwort hier seit Jahren verwendet.

Unter iOS 7 wird contentSize.height unabhängig vom Textinhalt zum frame.height-8.

Was ist eine Arbeitsmethode zum Anpassen der Höhe unter iOS 7?

64

Ich bevorzuge diese minimale Codeänderung: Fügen Sie einfach diese beiden Zeilen nach addSubview und vor dem Ergreifen der height der frame hinzu.

...
[scrollView1 addSubview: myTextView];

    [myTextView sizeToFit]; //added
    [myTextView layoutIfNeeded]; //added

CGRect frame = myTextView.frame;
...

Dies wird abwärtskompatibel mit iOS 6 getestet.NOTE, dass die Breite verkleinert wird. Wenn Sie nur an der Höhe interessiert sind und eine feste Breite haben, greifen Sie einfach auf die neue Höhe, stellen Sie jedoch die ursprüngliche Breite ein, und es funktioniert wie bisher unter iOS 6 und 7.

(Spekulation: Größe passt sich auch für iOS 7 an, das Layout wird jedoch später oder in einem separaten Thread aktualisiert. Dadurch wird das Layout sofort erzwungen, sodass der Frame rechtzeitig aktualisiert wird, um den Höhenwert a zu verwenden.) einige Zeilen später im selben Thread.)

ANMERKUNGEN:

1) Möglicherweise haben Sie die Größenänderung des äußeren Containers auf diese Weise implementiert. Es scheint jedoch ein allgemeines Snippet zu sein, und ich habe es in meinen Projekten verwendet.

2) Da sizeToFit unter iOS 7 wie erwartet zu funktionieren scheint, benötigen Sie wahrscheinlich nicht das vorzeitige addSubView. Ob es dann noch unter iOS 6 funktioniert, wird von mir nicht getestet.

3) Spekulation: Die zusätzliche Variable layoutIfNeeded kann teuer sein. Die Alternative ist, wie ich es sehe, die Größenänderung des äußeren Containers im Layout-Callback (ausgelöst oder nicht abhängig davon, ob das Betriebssystem entscheidet, ob ein Layout erforderlich ist oder nicht), wo die Größenänderung des äußeren Containers eine weitere Layoutaktualisierung verursacht. Beide Updates können mit anderen Layout-Updates kombiniert werden, um effizienter zu sein. Wenn Sie do eine solche Lösung haben und Sie zeigen können, dass es is effizienter ist, fügen Sie es als Antwort hinzu und ich werde es sicher hier erwähnen.

55

Da ich Auto Layout verwende, verwende ich den Wert von [textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)].height, um die constant der textView Höhe UILayoutConstraint zu aktualisieren.

33
ma11hew28

Ich verwende eine angepasste Version von Madmiks Antwort, die den Fudge-Faktor eliminiert:

- (CGFloat)measureHeightOfUITextView:(UITextView *)textView
{
    if ([textView respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
    {
        // This is the code for iOS 7. contentSize no longer returns the correct value, so
        // we have to calculate it.
        //
        // This is partly borrowed from HPGrowingTextView, but I've replaced the
        // magic fudge factors with the calculated values (having worked out where
        // they came from)

        CGRect frame = textView.bounds;

        // Take account of the padding added around the text.

        UIEdgeInsets textContainerInsets = textView.textContainerInset;
        UIEdgeInsets contentInsets = textView.contentInset;

        CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + textView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right;
        CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom;

        frame.size.width -= leftRightPadding;
        frame.size.height -= topBottomPadding;

        NSString *textToMeasure = textView.text;
        if ([textToMeasure hasSuffix:@"\n"])
        {
            textToMeasure = [NSString stringWithFormat:@"%@-", textView.text];
        }

        // NSString class method: boundingRectWithSize:options:attributes:context is
        // available only on ios7.0 sdk.

        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];

        NSDictionary *attributes = @{ NSFontAttributeName: textView.font, NSParagraphStyleAttributeName : paragraphStyle };

        CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
                                                  options:NSStringDrawingUsesLineFragmentOrigin
                                               attributes:attributes
                                                  context:nil];

        CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding);
        return measuredHeight;
    }
    else
    {
        return textView.contentSize.height;
    }
}
17
tarmes

Basierend auf anderen Antworten, habe ich es funktionieren lassen (in Swift) ... Das löst das Problem mit dem Zeilenumbruch-Charakter.

textView.sizeToFit()
textView.layoutIfNeeded()
let height = textView.sizeThatFits(CGSizeMake(textView.frame.size.width, CGFloat.max)).height
textView.contentSize.height = height

Auto Layout ist erforderlich.

16
MKatleast3

Wenn Sie das automatische Layout verwenden, können Sie eine triviale UITextView-Unterklasse erstellen, die die Höhe der Textansicht an den Inhalt anpasst:

@interface ContentHeightTextView : UITextView

@end

@interface ContentHeightTextView ()
@property (nonatomic, strong) NSLayoutConstraint *heightConstraint;
@end

@implementation ContentHeightTextView

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)];

    if (!self.heightConstraint) {
        self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height];
        [self addConstraint:self.heightConstraint];
    }

    self.heightConstraint.constant = size.height;

    [super layoutSubviews];
}

@end

Natürlich müssen Breite und Position der Textansicht durch zusätzliche Einschränkungen definiert werden, die an anderer Stelle im Programm konfiguriert werden.

Wenn Sie diese benutzerdefinierte Textansicht in IB erstellen, geben Sie der Textansicht eine Höhenbeschränkung, um Xcode zu erfüllen. Stellen Sie nur sicher, dass die in IB erstellte Höhenbeschränkung lediglich ein Platzhalter ist (d. h. das Kontrollkästchen "Zum Erstellungszeitpunkt entfernen" markieren).

enter image description here

Eine alternative Methode zum Implementieren der Unterklasse UITextView ist wie folgt (diese Implementierung kann als bewährte Methode angesehen werden):

@interface ContentHeightTextView ()
@property (nonatomic, strong) NSLayoutConstraint *heightConstraint;
@end

@implementation ContentHeightTextView

- (void)layoutSubviews
{
    [super layoutSubviews];

    [self setNeedsUpdateConstraints];
}

- (void)updateConstraints
{
    CGSize size = [self sizeThatFits:CGSizeMake(self.bounds.size.width, FLT_MAX)];

    if (!self.heightConstraint) {
        self.heightConstraint = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:size.height];
        [self addConstraint:self.heightConstraint];
    }

    self.heightConstraint.constant = size.height;
    [super updateConstraints];
}

@end
14
bilobatum

Wenn Sie das automatische Layout verwenden, können Sie die folgende UITextView-Unterklasse verwenden, die eine intrinsische Höhe hinzufügt:

@implementation SelfSizingTextView

- (void)setText:(NSString *)text
{
    [super setText:text];
    [self invalidateIntrinsicContentSize];
}

- (void)setFont:(UIFont *)font
{
    [super setFont:font];
    [self invalidateIntrinsicContentSize];
}

- (CGSize)intrinsicContentSize
{
    CGFloat width = self.frame.size.width;
    CGSize size = [self sizeThatFits:CGSizeMake(width, MAXFLOAT)];
    return CGSizeMake(UIViewNoIntrinsicMetric, size.height);
}

@end
4
phatmann

diese Methode scheint zu funktionieren.

// Code from Apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
- (CGFloat)measureHeight
{
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
{
    CGRect frame = internalTextView.bounds;
    CGSize fudgeFactor;
    // The padding added around the text on iOS6 and iOS7 is different.
    fudgeFactor = CGSizeMake(10.0, 16.0);

    frame.size.height -= fudgeFactor.height;
    frame.size.width -= fudgeFactor.width;

    NSMutableAttributedString* textToMeasure;
    if(internalTextView.attributedText && internalTextView.attributedText.length > 0){
        textToMeasure = [[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
    }
    else{
        textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
        [textToMeasure addAttribute:NSFontAttributeName value:internalTextView.font range:NSMakeRange(0, textToMeasure.length)];
    }

    if ([textToMeasure.string hasSuffix:@"\n"])
    {
        [textToMeasure appendAttributedString:[[NSAttributedString alloc] initWithString:@"-" attributes:@{NSFontAttributeName: internalTextView.font}]];
    }

    // NSAttributedString class method: boundingRectWithSize:options:context is
    // available only on ios7.0 sdk.
    CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
                                              options:NSStringDrawingUsesLineFragmentOrigin
                                              context:nil];

    return CGRectGetHeight(size) + fudgeFactor.height;
}
else
{
    return self.internalTextView.contentSize.height;
}
}
3
madmik3

Wenn Sie iOS 7+ verwenden, können Sie einfach das automatische Layout aktivieren, jede Seite der Textansicht an den Rand der übergeordneten Ansicht anheften, und es funktioniert einwandfrei. Kein zusätzlicher Code erforderlich.

1
Swindler

Wenn Sie im Storyboard Einschränkungen verwenden, stellen Sie sicher, dass Sie auf der Registerkarte "Lineal" des rechten Bereichs von xcode für die UITextView auf Ihr Superview beschränkt sind. Mein Problem war, dass ich eine Einschränkung von -80 Pkt. Auf 'Nachlaufender Raum' hatte. 

enter image description here

0
DanWebster

Die Antwort von bilobatum funktionierte perfekt mit dem automatischen Layout, d. H. Der Textansicht wurde eine Unterklasse zugewiesen.

Wenn Sie die Höhe der Textansicht begrenzen möchten, fügen Sie eine weitere Einschränkung hinzu (ich habe sie mithilfe des Storyboards hinzugefügt, d. H. Höhe <= 166 (Höhe je nach Bedarf)).

Reduzieren Sie in der Unterklasse dann die Priorität der Höhenbeschränkung auf 750 (self.heightConstraint.priority = 750), um einen Konflikt zwischen der in der Unterklasse hinzugefügten Höhenbeschränkung und der im Storyboard hinzugefügten Höhenbeschränkung zu vermeiden.

0
Sunil Bhosale

In iOS 8 erben Sie einige Inhalte, die von den übergeordneten Elementen versetzt sind, und die Sie auch loswerden müssen.

Ein Beispiel für eine Unterklasse

// Originally from https://github.com/Nikita2k/resizableTextView

#import "ResizableTextView.h"

@implementation ResizableTextView

- (void) updateConstraints {

    // calculate contentSize manually
    // ios7 doesn't calculate it before viewDidAppear and we'll get here before
    CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

    // set the height constraint to change textView height
    [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
        if (constraint.firstAttribute == NSLayoutAttributeHeight) {
            constraint.constant = contentSize.height;
            *stop = YES;
        }
    }];

    [super updateConstraints];
}

- (void)setContentOffset:(CGPoint)contentOffset
{
    // In iOS 8 we seem to be inheriting the content offset from the parent.
    // I'm not interested
}

@end
0
Johan Forssell

Ich habe eine Kategorie über UITextView geschrieben:

- (CGSize)intrinsicContentSize {
    return self.contentSize;
}

- (void)setContentSize:(CGSize)contentSize {
    [super setContentSize:contentSize];
    [self invalidateIntrinsicContentSize];
}

Wenn UIKit ihre contentSize setzt, passt UITextView ihren intrinsic content size an. Das spielt gut mit autolayout.

0
Mert Buran

Jungs, die Autolayout verwenden, und Ihr Sizetofit funktioniert nicht. Bitte überprüfen Sie einmal Ihre Breitenbeschränkung. Wenn Sie die Breitenbeschränkung verfehlt haben, ist die Höhe genau.

Sie müssen keine andere API verwenden. Nur eine Zeile würde das Problem beheben.

[_textView sizeToFit];

Hier war ich nur mit der Höhe beschäftigt, hielt die Breite fest und hatte die Breitenbeschränkung meines TextView im Storyboard verfehlt.

Und dies sollte die dynamischen Inhalte der Dienste zeigen.

Hoffe das könnte helfen ..

0
Swaroop S