Ser Pounce Ser Pounce - 11 days ago 7
iOS Question

Example of NSTextContainer with non regular shape?

Hi I'm working with the new

TextKit
API for iOS7 and I'm trying to produce a
UITextView
with an irregular shape. So far I have in a view controller:

-(void) loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,548)];

NSTextStorage *textStorage = [[NSTextStorage alloc] init];

NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager: layoutManager];

BaseTextContainer *textContainer = [[BaseTextContainer alloc] initWithSize:CGSizeMake(100, 100)];
[layoutManager addTextContainer: textContainer];

BaseTextView *textView = [[BaseTextView alloc] initWithFrame:CGRectMake(110,124, 100, 100) textContainer:textContainer];
textView.backgroundColor = [UIColor blueColor];
textView.editable = YES;
[self.view addSubview:textView];
}


Then in my subclassed
NSTextContainer
, I want to have a
mutablePath
drawn as the shape of the text container, but not sure how to accomplish this. I have:

- (BOOL) isSimpleRectangularTextContainer
{
return NO;
}

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
NSLog(@"TEST");
CGContextRef context = ctx;
CGSize layerSize = layer.frame.size;

CGAffineTransform transform = CGAffineTransformMakeScale(layerSize.width / self.initialSize.width, layerSize.height / self.initialSize.height);
CGMutablePathRef newGraphicMutablePath = CGPathCreateMutableCopyByTransformingPath(self.mutablePath, &transform);
CGContextAddPath(context, newGraphicMutablePath);

CGPathRelease(newGraphicMutablePath);
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
CGContextDrawPath(context, kCGPathFill);
}


Just a bit confused about how to get this to work. I cannot find an example anywhere of an
NSTextContainer
with an irregular shape.

Answer

There is no need for all that code constructing the Text Kit stack, as you are not modifying the architecture of the stack. Just start with a normal UITextView - let's say it's self.textView - and then assign one or more UIBezierPath objects to its exclusion paths:

self.tv.textContainer.exclusionPaths = myArrayOfBezierPaths;

These paths are exclusion paths, so for an ellipse you will want to make four paths, each one describing a corner of the text container.

Alternatively, you can build the Text Kit stack yourself so as to insert your own text container subclass, and modify where the text is allowed to go by overriding lineFragmentForProposedRect:, perhaps similar to what I do here: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch10p537exclusionPath2/ch23p813textKitShapes/MyTextContainer.swift

Some experiments:

enter image description here

enter image description here