12
votes

CTFRAMESETTERSUGGERFRESEDAMESEWITHCONSTRESSIONS Retourne parfois une taille incorrecte?

Dans le code ci-dessous, CTFRASESETTERSUGGERSFRESIQUESWITHCONSTRAINTES CODE> retourne parfois un CGSIZE CODE> avec une hauteur qui n'est pas assez grosse pour contenir tout le texte qui est transmis. J'ai regardé Cette réponse . Mais dans mon cas, la largeur de la zone de texte doit être constante. Y a-t-il un autre moyen / meilleur moyen de comprendre la bonne hauteur de ma chaîne attribuée? Merci!

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedString);
CGSize tmpSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, CGSizeMake(self.view.bounds.size.width, CGFLOAT_MAX), NULL); 
CGSize textBoxSize = CGSizeMake((int)tmpSize.width + 1, (int)tmpSize.height + 1);


0 commentaires

6 Réponses :


20
votes

CTFRAMESETTERSUGGERFRESIMESWITHCONTERINES () est cassé. J'ai déposé un bogue à ce moment-là. Votre alternative est d'utiliser CTFRAMESETTERCreateFrame () avec un chemin suffisamment élevé. Ensuite, vous pouvez mesurer le recto du CTFRAME que vous revenez. Notez que vous ne pouvez pas utiliser cgfloat_max pour la hauteur, car CareText utilise un système de coordonnées détourné de l'iPhone et localisera son texte au "haut" de la case. Cela signifie que si vous utilisez cgfloat_max , vous n'aurez pas assez de précision pour raconter la hauteur de la boîte. Je recommande d'utiliser quelque chose comme 10 000 comme votre taille, car c'est 10 fois plus grand que l'écran lui-même et donne suffisamment de précision pour le rectangle résultant. Si vous devez établir un texte encore plus grand, vous pouvez le faire plusieurs fois pour chaque section du texte (vous pouvez demander à CTFRAMEREF pour la plage de la chaîne d'origine qu'il a permis de disposer).


6 commentaires

Cgfloat_max est vraiment un problème dans l'affaire en cours, définissant la valeur à 100.000 semble fonctionner bien. Il est toujours étrange que je ne fais pas face à ce problème sur iOS5.


@GREGORYM: Oui, c'est pourquoi j'ai suggéré d'utiliser quelque chose comme 10 000, c'est la valeur que j'ai utilisée (assez grande pour être utile, suffisamment petite pour permettre toujours beaucoup de précision dans la partie fractionnelle).


Ceci est une ancienne réponse, mais comment obtenez-vous le cgre ou la hauteur d'un CTFRAME?


@Andrewpark: C'est légèrement compliqué. Vous devez calculer le recttacle de la dernière ligne dans le cadre et prenez la différence entre le bas de celui-ci et le haut de l'espace que vous avez donné à l'encadrement pour savoir combien d'espace il avait besoin.


@Kevinballard Merci d'avoir révisé cette question et la clarification!


Si vous utilisez zéro comme hauteur, il ne limite pas la hauteur à une hauteur. J'ai écrit une catégorie pour cette question qui fonctionne pour moi dans tous les cas. Voir Stackoverflow.com/Questtions/16586190/...



59
votes

CTFRASESETTERSUGGERFRESIMESWITHCONTERINES Fonctionne correctement. La raison pour laquelle vous obtenez une hauteur trop courte est à cause de la conduite du style de paragraphe par défaut attaché aux chaînes attribuées. Si vous ne fixez pas un style de paragraphe à la chaîne, le corsetext renvoie la hauteur nécessaire pour rendre le texte, mais sans espace entre les lignes. Cela m'a pris pour toujours pour comprendre. Rien dans la documentation ne l'orthographique. Je viens de remarquer que mes hauteurs étaient courtes d'un montant égal à (nombre de lignes X attendu leader). Pour obtenir le résultat de la hauteur, vous vous attendez à ce que vous puissiez utiliser le code comme suit:

NSString  *text = @"This\nis\nsome\nmulti-line\nsample\ntext."
UIFont    *uiFont = [UIFont fontWithName:@"Helvetica" size:17.0];
CTFontRef ctFont = CTFontCreateWithName((CFStringRef) uiFont.fontName, uiFont.pointSize, NULL);

//  When you create an attributed string the default paragraph style has a leading 
//  of 0.0. Create a paragraph style that will set the line adjustment equal to
//  the leading value of the font.
CGFloat leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender;
CTParagraphStyleSetting paragraphSettings[1] = { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &leading };

CTParagraphStyleRef  paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
CFRange textRange = CFRangeMake(0, text.length);

//  Create an empty mutable string big enough to hold our test
CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, text.length);

//  Inject our text into it
CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) text);

//  Apply our font and line spacing attributes over the span
CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont);
CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(string);
CFRange fitRange;

CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, bounds, &fitRange);

CFRelease(framesetter);
CFRelease(string);


5 commentaires

Alors, comment cela est-il fait lorsque vous avez plusieurs polices de la chaîne attribuée?


Vous pouvez ajouter l'attribut de paragraphe à la chaîne à l'aide de cfattributedstringsettattributes et n'accepte pas pour ClearotherAttributes


Il est toujours trop court pour moi, même en utilisant le code de Chris.


Merci pour l 'information excellente. Vous devriez libérer "le paragraphe".


Parfois, cette approche échoue pour moi, la hauteur est trop courte.



-6
votes

Je découvre enfin .. Lorsque vous utilisez CTFraResetSetSuggestFramesIserSwithConstruisainS Retourner CGSIZE pour dessiner du texte, la taille est considérée comme assez grosse (parfois) pour tout le texte, la dernière ligne n'est donc pas dessinée. J'ajoute 1 à la taille. retour, il semble être en ce moment.

quelque chose comme ceci:

suggesticesse = cgsizemake (suggéraSize.Width, suggérant une suggestion.Height + 1);


0 commentaires

2
votes

Merci à Chris Desalvo pour l'excellente réponse! Enfin finissant 16 heures de débogage. J'ai eu un peu de mal à comprendre la syntaxe Swift 3. Donc, partager la version Swift 3 de la définition du style de paragraphe.

let leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = leading      
mutableAttributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: textRange)


0 commentaires

1
votes

Travailler sur ce problème et suivre de nombreuses réponses différentes de plusieurs affiches, j'avais mis en place une solution pour tout problème de taille de texte correcte, pour moi CTFRASESETTERSUGGERFReseWithConstraints code> ne fonctionne pas correctement, donc nous avons besoin de Pour utiliser CTFRAMESETTERCreateFrame CODE>, puis mesurez la taille de cette trame (ceci est un uifont code> extension) c'est Swift 100% strong>

Références forte> p>

CTFraResetSuggestFramesWithConstraints Retourne parfois une taille incorrecte ? P>

Comment obtenir la grande hauteur du texte dessiné sur un CTFRAME P>

Utilisation de cfarraygetvalueTindex à Swift avec UNSAREPOINTER (AUPRESET) P>

static func measure(frame:CTFrame) ->CGSize {

        let lines = CTFrameGetLines(frame)
        let numOflines = CFArrayGetCount(lines)
        var maxWidth : Double = 0

        for index in 0..<numOflines {
            let line : CTLine = unsafeBitCast(CFArrayGetValueAtIndex(lines, index), to: CTLine.self)
            var ascent : CGFloat = 0
            var descent : CGFloat = 0
            var leading : CGFloat = 0
            let width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading)

            if(width > maxWidth) {
                maxWidth = width
            }
        }

        var ascent : CGFloat = 0
        var descent : CGFloat = 0
        var leading : CGFloat = 0


        CTLineGetTypographicBounds(unsafeBitCast(CFArrayGetValueAtIndex(lines, 0), to: CTLine.self), &ascent, &descent, &leading)
        let firstLineHeight = ascent + descent + leading

        CTLineGetTypographicBounds(unsafeBitCast(CFArrayGetValueAtIndex(lines, numOflines - 1), to: CTLine.self), &ascent, &descent, &leading)
        let lastLineHeight = ascent + descent + leading

        var firstLineOrigin : CGPoint = CGPoint(x: 0, y: 0)
        CTFrameGetLineOrigins(frame, CFRangeMake(0, 1), &firstLineOrigin);

        var lastLineOrigin : CGPoint = CGPoint(x: 0, y: 0)
        CTFrameGetLineOrigins(frame, CFRangeMake(numOflines - 1, 1), &lastLineOrigin);

        let textHeight = abs(firstLineOrigin.y - lastLineOrigin.y) + firstLineHeight + lastLineHeight

        return CGSize(width: maxWidth, height: Double(textHeight))
    }


0 commentaires

0
votes

Cela me conduisait Batty et aucune des solutions ci-dessus n'a travaillé pour que je puisse calculer la disposition des longues chaînes sur plusieurs pages et des valeurs de plage de retour avec des lignes complètement tronquées. Après avoir lu les notes d'API, le paramètre de CTFRAMESETTERSUGGERSFRAMESIMESAINTAINTINGS POUR «StringRange» est donc:

'La plage de cordes à laquelle la taille du cadre s'appliquera. La plage de cordes est une plage via la chaîne utilisée pour créer le cadrage. Si la partie longueur de la plage est réglée sur 0, le tramesetter continuera à ajouter des lignes jusqu'à ce qu'il soit hors du texte ou de l'espace. '

Après avoir réglé la plage de cordes sur 'CFLANGEMAKE (couranteLocation, 0)' au lieu de 'CFLANGEMAKE (couranteLocation, string.length)', tout fonctionne parfaitement.


0 commentaires