NSAttributedString justified text (without stretching words) - ios

I'm using justified text for my NSAttributedString in my UITextView:
var paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.Justified;
normalAttributes.setObject(paragraphStyle, forKey: NSParagraphStyleAttributeName)
The problem is that it stretches some words in order to achieve the justified alignment, instead of just stretching the spaces between the words. I find this very distracting and know there is a way to do such that words are not stretched, but only the spacing. Below is a screenshot from my app, followed by one from an app with some of the same functionality that also uses justified text and the exact same font.
How do I achieve the same effect?
Any help would be greatly appreciated.

There is a nasty trick which you can use.
You can use a UIWebView and css to do the alignment the way you want.
Here is a sample:
NSString *css = [NSString stringWithFormat:
#"<html><head><style>body { background-color: white; text-align: %#; font-size: %ipx; color: black;} a { color: #172983; } </style></head><body>",
#"justify",
11];
NSMutableString *desc = [NSMutableString stringWithFormat:#"%#%#%#",
css,
#"15 Προσέχετε ἀπὸ τῶν ψευδοπροφητῶν͵ οἵτινες ἔρχονται πρὸς ὑμᾶς ἐν ἐνδύμασι προβάτων͵ ἔσωθεν δέ εἰσι λύκοι ἅρπαγες. 16 ἀπὸ τῶν καρπῶν αὐτῶν",
#"</body></html>"];
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(20, 80, 150, 100)];
[self.view addSubview:webView];
[webView loadHTMLString:desc baseURL:nil];
And here is the result:

You just have to change the hyphenationFactor to 1:
textView.layoutManager.hyphenationFactor = 1

Related

NSString sizing does not account for Greek breathing marks

I've got an app that displays Greek text. I use the Cardo font for good display. In working on an AppleWatch extension and app, it was pointed out to me that some of the special characters are being cut off. This is how some example text should look (screenshot from an iPhone simulator):
Here is the same text on the Watch simulator:
Note that the fancy accent character (to be specific, a breathing mark with a circumflex accent) on the second character of the first word is cut off. I tried setting the label's frame on the phone using some NSString measuring code like this:
UILabel *label = [[UILabel alloc]init];
label.font = [UIFont fontWithName:#"Cardo" size:16];
[self.view addSubview:label];
label.text = #"οὗτος ἦλθεν εἰς μαρτυρίαν ἵνα μαρτυρήσῃ περὶ τοῦ φωτός, ἵνα πάντες πιστεύσωσιν δι᾽ αὐτοῦ.";
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc]init];
style.lineBreakMode = NSLineBreakByWordWrapping;
CGRect rect = [label.text boundingRectWithSize:self.view.bounds.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName: label.font,
NSParagraphStyleAttributeName: style} context:nil];
label.frame = CGRectMake(5, 100, ceilf(rect.size.width), ceilf(rect.size.height));
label.layer.borderWidth = 1; //for clarity
label.layer.borderColor = [UIColor blackColor].CGColor;
The result looks like this (the border is drawn for clarity's sake):
Interestingly, if I use the system font instead of Cardo, the extra symbols display correctly:
So, my question: What causes the NSString sizing to cut off the extra marks? Is there some option I can pass to the sizing method to correct this? Or better yet, is there some option I can set on the WKInterfaceLabel in the Watch app to get it to render correctly?
I don't know if this will fix it or not, but this will give you more to look into. I ran into an issue with a font using "Lower Case" numbers, which is a typography style for tabular numbers. I was able to create a variation of the font using a UIFontDescription that forced all numbers to be upper case. In your case the font's ascenders go over the top of the font's capHeight. There are a bunch of options for creating a font using a font descriptor and one of them may help. Here is how I created the upper case number font.
_font = [UIFont fontWithName:_fontName size:size];
NSArray* featureSettings = #[
#{
UIFontFeatureTypeIdentifierKey: #(kNumberCaseType),
UIFontFeatureSelectorIdentifierKey: #(kUpperCaseNumbersSelector)
}];
UIFontDescriptor* originalDescriptor = [_font fontDescriptor];
UIFontDescriptor* newDescriptor = [originalDescriptor fontDescriptorByAddingAttributes: #{UIFontDescriptorFeatureSettingsAttribute: featureSettings }];
_font = [UIFont fontWithDescriptor: newDescriptor size: size];
Specifically check out the kVerticalPositionType.
I actually ran into a case in my iOS app where the font ascenders where going over the capHeight from the baseline up and my attributed string was getting cut off. Since I was in quartz drawing code I just use the difference of the font's lineHeight with its ascender and padded the top. Unfortunately that is not an option on the Apple Watch.
I suspect the problem is in the font itself, with the ascenders being set too tightly for proper display.
I would first try setting the UILabel's text inset by making a subclass of UILabel and overriding drawTextInRect:
- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {5, 0, 0, 0};
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
If you have tried increasing the text inset to accommodate the font and it has not worked, take a look at Custom installed font not displayed correctly in UILabel

How can I make a UITextView layout text the same as a UILabel?

I have a UILabel that I need to convert to a UITextView because reasons. When I do this, the text is not positioned the same, despite using the same (custom) font.
I found that if I set:
textView.textContainer.lineFragmentPadding = 0;
textView.textContainerInset = UIEdgeInsetsZero;
This gets the text very close, but if I superimpose the UITextView over top of the UILabel, I see the text positioning get farther apart with each new line.
The UILabel is green, the UITextView is black. This is using NSParagraphStyle to set min and max line height to 15.
I've played with setting the paragraph style and min/max line height, but I haven't been able to match it exactly. I'm not a printer, so I don't necessarily understand all of the font related terms in the documentation for NSLayoutManager and NSTextContainer and all that.
I only need to support iOS 7 and up.
I'm not going to switch to some crazy CoreText-based custom widget or use some random third party library. I'm okay with close enough if I have to. But it seems like there should be some combination of random properties to make them layout the same.
I took the solution for line spacing found at this link and applied it to your issue. I managed to get it incredibly close by adjusting the lineSpacing property. I tested with HelveticaNeue size 13 and managed to get it to line up as shown in the screen shot below.
textView.textContainer.lineFragmentPadding = 0;
textView.textContainerInset = UIEdgeInsetsZero;
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = -0.38;
NSDictionary *attrsDictionary =
#{ NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue" size:13.0f],
NSParagraphStyleAttributeName: paragraphStyle};
textView.attributedText = [[NSAttributedString alloc] initWithString:textView.text attributes:attrsDictionary];
I've been able to successfully 'impersonate' a non-editable multiline UILabel (as it happens, in a UITableViewCell subclass) with an equivalent editable multiline UITextView using the following :
_textView = UITextView.new;
_textView.font = _label.font;
_textView.textColor = _label.textColor;
_textView.textAlignment = _label.textAlignment;
_textView.backgroundColor = UIColor.clearColor;
_textView.textContainer.lineFragmentPadding = 0;
_textView.textContainerInset = UIEdgeInsetsZero;
and to make it behave well when doing actual edits, add the following to your UITextViewDelegate:
- (void)textViewDidChange:(UITextView *)textView
{
...
[textView scrollRangeToVisible:NSMakeRange(textView.text.length, 0)];
[textView scrollRectToVisible:[textView caretRectForPosition:textView.endOfDocument] animated:NO];
}

scrolling in the bottom is not working

I am using a web view its working fine. but I am having a three issue 1.i want to change the font 2. change the size of font 3. when I scroll the web content to bottom it's not scrolling up to the bottom.
content=[[UIWebView alloc]init];
content.Frame=CGRectMake(10, 200, 300, 480);
[content loadHTMLString:content1 baseURL:nil];
[content loadHTMLString:[NSString stringWithFormat:#"<html><body background-colo r: transparent text=\"#eadfa8\" font-family=\"Arial Rounded MT Bold\" font-size=\".1\">%#</body></html>", [self.JSONData objectForKey:#"content"]] baseURL: nil];
[content stringByEvaluatingJavaScriptFromString: #"content.body.style.fontFamily = 'Arial'"];
content.opaque=YES;
[self.view addSubview:content];
[content setBackgroundColor:[UIColor clearColor]];
[content setOpaque:NO];
above html coding I try to change the font family to Arial but its not working. help me .
For First two issues answer is Font change inside UIWebView
The third issue you can overcome by below lines
content.scalesPageToFit=TRUE;
content.scrollView.bounces = NO;

Horizontal Scrolling in UIWebView Not Working

I've looked around for a while and there seems to be quite a few questions on scrolling in UIWebView, but none of the solutions have worked for me. I have a UIWebView inside a view on one of the pages of my app:
myWebView = [[UIWebView alloc] initWithFrame:b];
[myWebView.scrollView setContentSize:CGSizeMake(1136, 400)];
[myWebView loadHTMLString:styleSheet baseURL:nil];
[myView addSubview:myWebView];
Right now, scrolling vertically works fine, but changing contentSize seems to not affect anything.
I need to display a small spreadsheet and making the view wider will make it much more readable.
To set the height of the webView page in HTML do this:
myWebView = [[UIWebView alloc] initWithFrame:b];
[myWebView loadHTMLString:styleSheet baseURL:nil];
[myView addSubview:myWebView];
where styleSheet is a NSString with this HTML Code:
NSString *styleSheet = [NSString stringWithFormat:#"html { min-width: 100%%; min-height: 100%%; } body { width: %dpx; height: %dpx; background-color: #FFF; }", myWebView.frame.size.width*2, myWebView.frame.size.height*2];
(width*2 and height*2 for retina display)
You can of course add anything you want to the HTML string to change the content of the webView.

iOS 5 : bug with loadHTMLString with style

I have these lines of code:
NSString *html = [NSString stringWithFormat:
#"<html><body><p \"style=\"font-size:%d; text-align:center; color:red; \
direction:rtl;\">%#</p></body</html>", fontSize, thePage];
mailBody.text = thePage;
[self.page loadHTMLString:html baseURL:nil];
Styling didn't take any effect at all. So, direction isn't set, color is black instead of red and the font-size isn't set to the number I put in the variable. Yet, it's working in pre iOS 5.
There is a problem in your HTML
USE THIS
NSString* html = [NSString stringWithFormat:#"<html><body><p style=\"font-size:%d;text-align:center; color:red; direction:rtl;\">%#</p></body></html>",fontSize,thePage];

Resources