How to change font in NSTextContainer - objective-c

My application is setup as so.
Custom UIView inside a ScrollView.
The custom UIView is getting text generated on top of it with this code.
CoreDavening.m draw function
attStorage = [[NSTextStorage alloc]initWithAttributedString:string];
textContainer = [[NSTextContainer alloc]
initWithSize:CGSizeMake(self.frame.size.width, FLT_MAX)];
layoutManager = [[NSLayoutManager alloc]init];
[layoutManager addTextContainer:textContainer];
[attStorage addLayoutManager:layoutManager];
NSRange glyphRange = [layoutManager
glyphRangeForTextContainer:textContainer];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: rect.origin];
In my ViewController.m I'm creating the view like so.
CoreDavening *davenView = [[CoreDavening alloc]initWithFrame:CGRectMake(0, 0,self.view.frame.size.width, [coreDavening heightForStringDrawing])];
davenView.backgroundColor = [UIColor whiteColor];
davenView.layer.borderColor = [[UIColor whiteColor]CGColor];
scrollView.backgroundColor = [UIColor whiteColor];
[scrollView addSubview:davenView];
self.scrollView.contentSize = davenView.frame.size;
Im trying to find a way to 1) change the font size (just size) 2) have the scrollView and CustomView resize appropriately.
How can this be done?
EDIT 1:
Im creating the custom view in my viewController like this.
CoreDavening *coreDavening = [[CoreDavening alloc]init];
davenView = [[CoreDavening alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, [coreDavening heightForStringDrawing ])];
and updating/refreshing the custom view like this.
It get triggered when the slider I have set up changes value.
- (IBAction)sliderChanged:(id)sender {
NSUserDefaults *prefs= [NSUserDefaults standardUserDefaults];
[prefs setInteger:(long)self.Slider.value forKey:#"fontSize"];
[prefs synchronize];
[davenView setNeedsLayout];
}
My custom view controller has the font set up like.
THIS IS IN THE DRAW FUNCTION
attStorage = [[NSTextStorage alloc]initWithAttributedString:string];
[attStorage addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:(long)[prefs integerForKey:#"fontSize"]] range:NSMakeRange(0, attStorage.length)];
textContainer = [[NSTextContainer alloc]
initWithSize:CGSizeMake(self.frame.size.width, FLT_MAX)];
layoutManager = [[NSLayoutManager alloc]init];
[layoutManager addTextContainer:textContainer];
[attStorage addLayoutManager:layoutManager];
NSRange glyphRange = [layoutManager
glyphRangeForTextContainer:textContainer];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: rect.origin];

It seems like you have the textStorage associated with the layoutManager already. NSTextStorage is the subclass of NSMutableAttributedString. So, this is the class which is responsible to hold the layout and styling information. How have you created your textStorage ? Besides, the styling, NSTextStorage also has methods to allow editing the contents and have dynamic styling.
You can simply set the attribute to your textStorage if you want to change the font.
[_textStorage addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:20.0] range:NSMakeRange(0, _textStorage.length)];
NSTextManager class has quite useful methods to find the bounds and glyphs informations. So, you could use method like below to find the bounds for your text,
- (CGRect)boundingRectWithSize:(CGSize)size
{
self.textContainer.size = size;
NSRange glyphRange = [self.layoutManager glyphRangeForTextContainer:self.textContainer];
CGRect boundingRect = [self.layoutManager boundingRectForGlyphRange:glyphRange
inTextContainer:self.textContainer];
boundingRect.origin.x = 0;
boundingRect.origin.y = 0;
return boundingRect;
}

Related

how to make NSTextField to fit NSMutableAttributedString contained

I have a NSTextField where I add NSMutableAttributedString. I want to set the size of that string to big number, however when I do that the text appears cut off. How can tell the NSTextField to get bigger?
This is what I have:
NSTextField* textField = [[NSTextField alloc] init];
NSMutableAttributedString* text = [[NSMutableAttributedString alloc]
initWithString:#"0"];
NSRange titleRange = NSMakeRange(0, [text length]);
[text addAttribute:NSFontAttributeName
value:[NSFont boldSystemFontOfSize:25]
range:titleRange];
[textField setAttributedStringValue:text];
Any advice?
Thanks in advance
Make a subclass of NSTextField
In implementation do override intrinsicContentSize
-(NSSize)intrinsicContentSize
{
if ( ![self.cell wraps] ) {
return [super intrinsicContentSize];
}
NSRect frame = [self frame];
CGFloat width = frame.size.width;
frame.size.height = CGFLOAT_MAX;
CGFloat height = [self.cell cellSizeForBounds: frame].height;
return NSMakeSize(width, height);
}
// Than invalidate the layout when text changes
- (void)textDidChange:(NSNotification *)notification
{
[super textDidChange:notification];
[self invalidateIntrinsicContentSize];
}
In attribute Inspector inside storyboard set NSTextField class to your customNSTextField class and change layout to wraps from scrolls.
You must add constraints to your textField to its superview, easier in storyboard.
After that you can also set font size directly :
[_textField setFont:[NSFont systemFontOfSize:25]];
[textField sizeToFit];
But using autolayout, is usually a better idea.

Showing NSAttributedString at the Center With NSView

I have the following function to make an attributed string.
- (NSMutableAttributedString *)makeText:(NSString *)txt : (NSString *)fontname : (CGFloat)tsize :(NSColor *)textColor :(NSColor *)shadowColor :(NSSize)offset {
NSShadow *shadow = [[NSShadow alloc] init];
shadow.shadowColor = shadowColor;
shadow.shadowOffset = offset;
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 10.0f;
paragraphStyle.alignment = NSCenterTextAlignment;
NSMutableAttributedString *atext = [[NSMutableAttributedString alloc] initWithString:txt];
NSRange range = NSMakeRange(0,txt.length);
// alignment
[atext addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0,[atext length])];
...
...
return atext;
}
If I set this attributed string to NSTextField, the resulting attributed string will be aligned correctly. But if I send it to NSView's subclass, the string will be left-aligned. Is there any way by which I can display this attributed string with correct alignment?
// .h
#interface imageView1 : NSView {
NSAttributedString *aStr;
}
// .m
- (void)drawRect:(NSRect)dirtyRect {
[aStr drawAtPoint:NSMakePoint((self.frame.size.width-aStr.size.width)/2.0f,(self.frame.size.height-aStr.size.height)/2.0f)];
}
Thank you for your help. The OS version is 10.8.
If you draw at a point there are no bounds in relation to which to center. You need to specify a rect. See the docs on drawWithRect:options:. Note the admonition there pointing out that to be in that rect your options will need to be (or include) NSStringDrawingUsesLineFragmentOrigin.

replace layout manager of uitextview

NSTextContainer on Mac OS X has a method replaceLayoutManager: to replace the NSLayoutManager of NSTextView with a subclass of NSLayoutManager.
Unfortunately iOS doesn't have such a function.
I tried a combination of these lines of code, but it keeps crashing.
THLayoutManager *layoutManager = [[THLayoutManager alloc] init];
[layoutManager addTextContainer:[self textContainer]];
// [[self textStorage] removeLayoutManager:[self layoutManager]];
//[[self textStorage] addLayoutManager:layoutManager];
[[self textContainer] setLayoutManager:layoutManager];
What is the correct procedure to replace the NSLayoutManager of an UITextview?
Since iOS9, NSTextContainer has the same method as macOS. So now you can replace the layout manager on your storyboard UITextView with your own subclass:
textView.textContainer.replaceLayoutManager(MyLayoutManager())
Have a look at the WWDC2013 Intro To Text Kit video and sample code where they show how to do it.
https://developer.apple.com/downloads/index.action?name=WWDC%202013
https://developer.apple.com/wwdc/videos/
Below is an extract from the code
-(void)viewDidLoad
{
[super viewDidLoad];
// our auto layout views use a design spec that calls for
// 8 pts on each side except the bottom
// since we scroll at the top here, only inset the sides
CGRect newTextViewRect = CGRectInset(self.view.bounds, 8., 0.);
self.textStorage = [[TKDInteractiveTextColoringTextStorage alloc] init];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(newTextViewRect.size.width, CGFLOAT_MAX)];
container.widthTracksTextView = YES;
[layoutManager addTextContainer:container];
[_textStorage addLayoutManager:layoutManager];
UITextView *newTextView = [[UITextView alloc] initWithFrame:newTextViewRect textContainer:container];
newTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
newTextView.scrollEnabled = YES;
newTextView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
[self.view addSubview:newTextView];
self.textView = newTextView;
self.textStorage.tokens = #{ #"Alice" : #{ NSForegroundColorAttributeName : [UIColor redColor] },
#"Rabbit" : #{ NSForegroundColorAttributeName : [UIColor orangeColor] },
TKDDefaultTokenName : #{ NSForegroundColorAttributeName : [UIColor blackColor] } };
}

How to add text shadows to a UITextView?

I've been searching around to find an easy way to add shadows to the text of a UITextView, like you can do in a UILabel. I found this question where there was an answer that supposedly does this, however, it makes no sense why this should be the case.
Question: Adding shadows to the layer of the UITextView itself should not affect the text inside, rather it should shadow the entire object, right?
In my case, even adding the shadow to the layer of the textview is not having any effect (even after adding the QuartzCore headers).
i tried, and found that , you should set the UITextView's backgroundcolor to transparent,
so the shadow should work
UITextView *text = [[[UITextView alloc] initWithFrame:CGRectMake(0, 0, 150, 100)] autorelease];
text.layer.shadowColor = [[UIColor whiteColor] CGColor];
text.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
text.layer.shadowOpacity = 1.0f;
text.layer.shadowRadius = 1.0f;
text.textColor = [UIColor blackColor];
//here is important!!!!
text.backgroundColor = [UIColor clearColor];
text.text = #"test\nok!";
text.font = [UIFont systemFontOfSize:50];
[self.view addSubview:text];
#adali's answer will work, but its wrong. You shouldn't add the shadow to the UITextView itself in order to effect the visible views inside. As you can see, by applying the shadow to the UITextView the cursor will also have the shadow.
The approach that should be used is with NSAttributedString.
NSMutableAttributedString* attString = [[NSMutableAttributedString alloc] initWithString:textView.text];
NSRange range = NSMakeRange(0, [attString length]);
[attString addAttribute:NSFontAttributeName value:textView.font range:range];
[attString addAttribute:NSForegroundColorAttributeName value:textView.textColor range:range];
NSShadow* shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor whiteColor];
shadow.shadowOffset = CGSizeMake(0.0f, 1.0f);
[attString addAttribute:NSShadowAttributeName value:shadow range:range];
textView.attributedText = attString;
However textView.attributedText is for iOS6. If you must support lower versions, you could use the following approach.
CALayer *textLayer = (CALayer *)[textView.layer.sublayers objectAtIndex:0];
textLayer.shadowColor = [UIColor whiteColor].CGColor;
textLayer.shadowOffset = CGSizeMake(0.0f, 1.0f);
textLayer.shadowOpacity = 1.0f;
textLayer.shadowRadius = 0.0f;

Is it possible to change the header height of an NSTextView?

I am saving a PDF from an NSTextview and putting a logo in the header. I overrode pageHeader and the logo appears but it is clipped.
Is it possible to change the header height of an NSTextView?
Thanks!
Partial code:
-(IBAction)impLaudo:(id)sender
{
NSPrintInfo *printInfo;
NSPrintInfo *sharedInfo;
NSPrintOperation *printOp;
NSMutableDictionary *printInfoDict;
NSMutableDictionary *sharedDict;
sharedInfo = [NSPrintInfo sharedPrintInfo];
sharedDict = [sharedInfo dictionary];
printInfoDict = [NSMutableDictionary dictionaryWithDictionary:sharedDict];
[printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
[printInfoDict setObject:[[dirLaudos stringByAppendingString:[estudo stringValue]] stringByAppendingString:#".pdf"] forKey:NSPrintSavePath];
printInfo = [[NSPrintInfo alloc] initWithDictionary: printInfoDict];
[printInfo setHorizontalPagination: NSClipPagination];
[printInfo setVerticalPagination: NSAutoPagination];
[printInfo setVerticallyCentered:NO];
[[printInfo dictionary] setValue:[NSNumber numberWithBool:YES] forKey:NSPrintHeaderAndFooter];
printOp = [NSPrintOperation printOperationWithView:textView printInfo:printInfo];
[printOp setShowsPrintPanel:NO];
[printOp runOperation];
}
#implementation MyTextView
- (NSAttributedString *)pageHeader
{
// Adicionando cabeƧalho
NSAttributedString *theHeader = nil;
NSImage * pic = [[NSImage alloc] initWithContentsOfFile:[dirLayout stringByAppendingString:#"cabecalho.jpg"]];
NSTextAttachmentCell *attachmentCell = [[NSTextAttachmentCell alloc] initImageCell:pic];
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
[attachment setAttachmentCell: attachmentCell ];
theHeader = [NSAttributedString attributedStringWithAttachment: attachment];
return theHeader;
}
#end
Instead of overriding -pageHeader, you should override -drawPageBorderWithSize:, which allows you to draw additional marks on the page at print time.
The Size parameter is an NSSize struct containing the size of the current logical page. All you need to do is draw your logo in the correct location:
- (void)drawPageBorderWithSize:(NSSize)pageSize
{
[super drawPageBorderWithSize:pageSize];
//draw your logo
NSPoint offset = NSMakePoint(100.0, 100.0);
NSImage* logo = [NSImage imageNamed:#"logo"];
NSSize logoSize = [logo size];
NSPoint imageOrigin = NSMakePoint(offset.x, pageSize.height - (offset.y + logoSize.height));
[self lockFocus];
[logo drawInRect:NSMakeRect(imageOrigin.x, imageOrigin.y, logoSize.width, logoSize.height)
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0
respectFlipped:YES
hints:nil];
[self unlockFocus];
}