NSAttributedString vertikal zentrieren

  • RE: NSAttributedString vertikal zentrieren

    NSAttributedString hat die Methode size. Damit solltest Du die bounding box des Strings erhalten. Um den String dann in einem NSRect zu zentrieren, einfach x mit:

    Quellcode

    1. x = NSMidX(rect) - size.width / 2
    brechnen und den NSAttributedString mit drawAtPoint: ausgeben.
  • RE: NSAttributedString vertikal zentrieren

    aber achtung, diese methoden (size und drawAtPoint:) sind arschlangsam. Da wir bei jedem Aufruf ein komplett neues Textsystem aufgesetzt und wieder gelöscht. Also nur für kurze Texte und schwache Nutzung brauchbar.
  • RE: NSAttributedString vertikal zentrieren

    Jepp, diese einfachen Operationen mal zwischendurch sheen einfach aus. In Wirklichkeit wird die Arbeit nur ins Interne verlagert. Wenn man kleine Textchen hat (Beschriftungen etwa), so ist es durchaus naheliegend geomatrische Verhältnisse und auch die Zeichen (als Bezier-Pfade) zwischenzuspeichern. Das bringt recht viel.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • RE: NSAttributedString vertikal zentrieren

    Ich kann nicht nachvollziehen wieso das komplette Textsystem in OS X so schnarch langsam ist. Ok dort werden Vektor Fonts für jede beliebige Auflösung mit Antialias und weiterem Schnick-Schnack berechnet, aber OS X legt da schon eine extreme Gemütlichkeit an den Tag.

    Douglas Davidson, der Textsystem Guru bei Apple, hat auf der WWDC gesagt, dass das Textsystem für Leopord überarbeitet wurde und viel schneller wird. Da meine Apps jedoch auch unter Tiger laufen, da nicht alle User direkt auf Leopard umsteigen werden bringt dies leider auch nicht viel. Die sollten die neuen Textsystem Routinen dann vielleicht mal als Patch für Tiger anbieten.
  • RE: NSAttributedString vertikal zentrieren

    Original von Tom9811
    Wenn man kleine Textchen hat (Beschriftungen etwa), so ist es durchaus naheliegend geomatrische Verhältnisse und auch die Zeichen (als Bezier-Pfade) zwischenzuspeichern.

    Wie kann ich denn einen Text in einem Bezier-Pfad speichern?
  • RE: NSAttributedString vertikal zentrieren

    -appendBezierPathWithGlyphs:(NSBezierPath). Hier mal ein alter Code, der aber mitten aus der Arbeit gerissen sien kann. Aber fürs Prinzip reicht es allemale.

    Quellcode

    1. - (NSRect)makeBezierPathForSymbolWithLayoutManager:(NSLayoutManager*)layoutManager {
    2. int symbolIndex;
    3. NSRange stringRange;
    4. int numberOfGlyphs;
    5. NSGlyph glyphs[8];
    6. NSTextStorage* storage;
    7. NSBezierPath* bezierPath;
    8. NSRect unionRect = NSMakeRect( 0.0, 0.0, 0.0, 0.0 );
    9. NSMutableArray* symbolPaths = [NSMutableArray arrayWithCapacity:[self numberOfSymbols]];
    10. for( symbolIndex = 0; symbolIndex < [self numberOfSymbols]; symbolIndex++ ) {
    11. // Get the length of the string
    12. stringRange = NSMakeRange( 0, [[[self symbolSet] objectAtIndex:symbolIndex] length] );
    13. storage = [[[NSTextStorage alloc] initWithString:[[self symbolSet] objectAtIndex:symbolIndex]] autorelease];
    14. [storage setFont:[self font]];
    15. [storage addLayoutManager:layoutManager];
    16. // Check, whether array is big enough, otherwise add an empty bezier path
    17. if( stringRange.length > 8 ) {
    18. // if not, use an empty bezier path
    19. [symbolPaths addObject:[NSBezierPath bezierPath]];
    20. } else {
    21. // otherwise construct the path and check the rect
    22. numberOfGlyphs = [layoutManager getGlyphs:glyphs range:stringRange];
    23. bezierPath=[NSBezierPath bezierPath];
    24. [bezierPath moveToPoint:NSMakePoint( 0.0, 0.0)];
    25. [bezierPath appendBezierPathWithGlyphs:glyphs count:numberOfGlyphs inFont:[self font]];
    26. unionRect = NSUnionRect( unionRect, [bezierPath bounds] );
    27. [symbolPaths addObject:bezierPath];
    28. }
    29. }
    30. [self setSymbolPaths:symbolPaths];
    Alles anzeigen
    Ah, noch ein Hinweis. Ich glaube, dass der Boundary-Check für das Glyph-Array nicht korrekt ist. Für meine Zwecke hat er bloß gereicht.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • RE: NSAttributedString vertikal zentrieren

    Es hängt schon ein bisschen damit zusammen, wie du es "bedienst". Das Problem ist nur, dass man viel zu wenig Infos dafür hat.

    Es ahnt ja auch kein Mensch ohne Weiteres, dasss bei einem simplen convenient Draw das ganze Dingens einmal umgestülpt wird. Mittlerweile steht es wenigstens in der Doku. Wie gesagt: Bei Fällen wie bei dir, ist es ja so, dass du zahlreiche einzelne und unabhängige Textelemente hast, so dass du einen Großteil der Arbeit einmal pro Element machen kannst, um dann das Ergebnis zu speichern. Bloß: Wenn du natürlich in einer Tabelle bei jedem Redraw 12368172 Textsystapel instanzierst (oder auch nur initialisierst, weil du an ihnen "herumspielst"), wird das halt schnarch langsam.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Original von Objcler
    Falls ich allerdings mit drawAtPoint zeichne wird der String nicht automatisch in zwei Zeilen dargestellt, falls er nicht ein eine Zeile passt.

    Stimmt, dann musst Du doch das Text System direkt verwenden.

    Quellcode

    1. // Diesen Teil im init Deiner custom class verwenden
    2. NSTextStorage *textStorage = [[NSTextStorage alloc] init];
    3. NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    4. [layoutManager setUsesScreenFonts:YES];
    5. [textStorage addLayoutManager:layoutManager];
    6. NSTextContainer *textContainer = [[NSTextContainer alloc] init];
    7. [textContainer setLineFragmentPadding:0.0];
    8. [layoutManager addTextContainer:textContainer];
    9. [textContainer release];
    10. [layoutManager release];
    11. // Ab hier, wenn sich der Text mal ändern sollte!
    12. NSMutableDictionary *attr = nil;
    13. NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    14. [paragraphStyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
    15. [paragraphStyle setAlignment:NSCenterTextAlignment];
    16. [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
    17. [attr setValue:paragraphStyle forKey:NSParagraphStyleAttributeName];
    18. [paragraphStyle release];
    19. NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"Mein Text!" attributes:attr];
    20. [textStorage setAttributedString:attrString];
    21. [textStorage setFont:[style font]];
    22. [attrString release];
    23. // Ab hier, wenn sich das imageRect ändern sollte!
    24. [textContainer setContainerSize:imageRect.size];
    25. [layoutManager glyphRangeForTextContainer:textContainer];
    26. NSRect textRect = [layoutManager usedRectForTextContainer:textContainer];
    27. NSPoint point;
    28. point.x = NSMidX(imageRect) - NSWidth(textRect) / 2;
    29. point.y = NSMidY(imageRect) - NSMaxY(textRect) / 2;
    30. NSRange drawRange = [layoutManager glyphRangeForTextContainer:textContainer];
    31. // Hier wird der Text dann ausgegeben
    32. [layoutManager drawBackgroundForGlyphRange:drawRange atPoint:point];
    33. [layoutManager drawGlyphsForGlyphRange:drawRange atPoint:point];
    34. // spätestens im dealloc
    35. [textStorage release];
    Alles anzeigen
    Wenn Du textStorage, textRect, point und drawRange als Variablen Deiner custom class definierst, dann sollte die Ausgabe sehr schnell sein. Der Code ist jetzt nicht getestet, solle aber funktionieren.

    Bei Fragen einfach noch mal melden.
  • RE: NSAttributedString vertikal zentrieren

    Original von MCDan
    Douglas Davidson, der Textsystem Guru bei Apple, hat auf der WWDC gesagt, dass das Textsystem für Leopord überarbeitet wurde und viel schneller wird. Da meine Apps jedoch auch unter Tiger laufen, da nicht alle User direkt auf Leopard umsteigen werden bringt dies leider auch nicht viel. Die sollten die neuen Textsystem Routinen dann vielleicht mal als Patch für Tiger anbieten.


    So weit ich weiß, wird sich an den Routinen und der Struktur so ziemlich null ändern. Das einzige was so groß dazukommen soll, ist das Layout ohne den Text drüber gelayoutet zu haben. D.h. du kannst sofort ans Ende eines Textes scrollen. Das ganze geht über einen einzigen Setter einzuschalten.
    Der Rest wird sicher nur neu implementiert worden sein. Ich glaube nicht, dass es überhaupt möglich wäre, das komplett umzubauen, da dann jede Kompatiblität fehlen würde...

    Max
  • Original von MCDan
    Original von Objcler
    Falls ich allerdings mit drawAtPoint zeichne wird der String nicht automatisch in zwei Zeilen dargestellt, falls er nicht ein eine Zeile passt.

    Stimmt, dann musst Du doch das Text System direkt verwenden.


    Man kann es aber auch voll-geeky machen und den Spaß von Hand implementieren. Ich hab das bei mir gemacht, um versteckte Zeichen (Space, Enter, etc.) anzeigen zu lassen. Ist immernoch wesentlich langsamer als das von Apple, aber als User merkt man das nicht.

    z.B. so:

    Quellcode

    1. CGContextSetFont(context, CGFontCreateWithPlatformFont((void *)&fontRef));
    2. CGContextSetRGBFillColor(context, [_hiddenCharactersColor redComponent], [_hiddenCharactersColor greenComponent], [_hiddenCharactersColor blueComponent], [_hiddenCharactersColor alphaComponent]);
    3. CGContextSetFontSize(context, [font pointSize] * 0.7);
    4. CGContextShowGlyphsAtPoint(context, location.x, location.y, &glyph, 1);


    Max
  • RE: NSAttributedString vertikal zentrieren

    Ich hatte ihn so verstanden, dass das Textsystem intern überarbeitet wurde und somit unter Leopard eine bessere Performance bietet.

    Ich kann nur nicht ganz nachvollziehen, warum diese neuen internen Routinen dann nicht auch für Tiger über ein Update z.B. mit 10.4.9 zur Verfügung gestellt werden.

    Na ja, andererseits möchte Apple ja auch Leopard entsprechend vermarkten.