Dieses leicht mit Text Kit
getan werden kann. Ich mache sowas in meiner App. Der Unterschied besteht darin, dass ich Boxen (bei Bedarf verschachtelt) verwende, um jeden Textblock zu markieren. Hier ist, was Sie tun sollten:
Parse html string (oder was auch immer Sie Text verwenden markieren), markieren Sie jeden Textblock Zitat mit einem benutzerdefinierten Attribut, wie MyTextBlockAttribute
, speichern Bereiche jeder Textblock (dBlock quote) und fügen Sie es als Attribut dem verwandten Bereich der attributierten Zeichenfolge hinzu (konstruieren Sie diese attributierte Zeichenfolge aus Ihrem Inhalt) und der Liste, die an den Inhalt angehängt ist. Rufen wir diese Liste MyTextBlockList
.
zeichnen Sie Text mit Text Kit
selbst. Zeichne zuerst den Hintergrund (weiße Farbe, hellgraue Farbe usw.), zeichne Text oder vertikale Linien als nächstes. Da Sie den Bereich jedes Textblocks durch Schleifen durch die Liste abrufen können, können Sie diese Blöcke mit der Methode [NSLayoutManager range: inTextContainer:textContainer]
umgrenzen.
Hier ist der Code, den ich in meiner Anwendung verwendet wird:
// subclass of NSTextContainer
#import "MyTextContainer.h"
#import "MyBlockAttribute.h"
@interface MyTextContainer()
@property (nonatomic) BOOL isBlock;
@end
@implementation MyTextContainer
- (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect
atIndex:(NSUInteger)characterIndex
writingDirection:(NSWritingDirection)baseWritingDirection
remainingRect:(CGRect *)remainingRect {
CGRect output = [super lineFragmentRectForProposedRect:proposedRect
atIndex:characterIndex
writingDirection:baseWritingDirection
remainingRect:remainingRect];
NSUInteger length = self.layoutManager.textStorage.length;
MyTextBlockAttribute *blockAttribute;
if (characterIndex < length) {
blockAttribute = [self.layoutManager.textStorage attribute:MyTextBlockAttributeName atIndex:characterIndex effectiveRange:NULL]; // MyTextBlockAttributeName is a global NSString constant
}
if (blockAttribute) { // text block detected, enter "block" layout mode!
output = CGRectInset(output, blockAttribute.padding, 0.0f); // set the padding when constructing the attributed string from raw html string, use padding to control nesting, inner boxes have bigger padding, again, this is done in parsing pass
if (!self.isBlock) {
self.isBlock = YES;
output = CGRectOffset(output, 0.0f, blockAttribute.padding);
}
} else if (self.isBlock) {
self.isBlock = NO; // just finished a block, return back to the "normal" layout mode
}
// no text block detected, not just finished a block either, do nothing, just return super implementation's output
return output;
}
@end
// drawing code, with drawRect: or other drawing technique, like drawing into bitmap context, doesn't matter
- (void)drawBlockList:(NSArray *)blockList content:(MyContent *)content {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 0.5f);
[[UIColor colorWithWhite:0.98f alpha:1.0f] setFill];
CGContextSaveGState(context);
MyTextContainer *textContainer = content.textContainer;
// since I draw boxes, I have to draw inner text block first, so use reverse enumerator
for (MyTextBlockAttribute *blockAttribute in [blockList reverseObjectEnumerator]) {
if (blockAttribute.noBackground) { // sometimes I don't draw boxes in some conditions
continue;
}
CGRect frame = CGRectIntegral([content.layoutManager boundingRectForGlyphRange:blockAttribute.range inTextContainer:textContainer]);
frame.size.width = textContainer.size.width - 2 * (blockAttribute.padding - MyDefaultMargin); // yeah... there is some margin around the boxes, like html's box model, just some simple math to calculate the accurate rectangles of text blocks
frame.origin.x = blockAttribute.padding - MyDefaultMargin;
frame = CGRectInset(frame, 0, -MyDefaultMargin);
if (blockAttribute.backgroundColor) { // some text blocks may have specific background color
CGContextSaveGState(context);
[blockAttribute.backgroundColor setFill];
CGContextFillRect(context, frame);
CGContextRestoreGState(context);
} else {
CGContextFillRect(context, frame);
}
CGContextStrokeRect(context, frame); // draw borders of text blocks in the last
}
CGContextRestoreGState(context);
}
- (UIImage *)drawContent:(MyContent *)content {
UIImage *output;
UIGraphicsBeginImageContextWithOptions(content.bounds.size, YES, 0.0f); // bounds is calculated in other places
[[UIColor whiteColor] setFill];
UIBezierPath *path = [UIBezierPath bezierPathWithRect:content.bounds];
[path fill];
[self drawBlockList:content.blockList content:content]; // draw background first!
[content.layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, content.textStorage.length) atPoint:CGPointZero]; // every content object has a set of Text Kit core objects, textStorage, textContainer, layoutManager
output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return output;
}
In Ihrem Fall, Sie nicht Boxen zeichnen Sie Grenzen zeichnen statt links. Die Technik ist die gleiche, hoffe das kann dir helfen!
Wie würde ich NSAttributedString dafür verwenden? –
Leider habe ich kein Schnipsel dafür, das Hauptproblem wäre mit der farbigen Umrandung, die Sie einen Bildanlage-Check hier http://www.objc.io/issue-5/getting-to-know-textkit verwenden können .html – Andrea