For UIWebview: basically the accepted answer doesn't address the UIWebView
case.. So here is a way I addressed this problem.
first: Using hpple, an obj-c HTML parser, I went through the html and basically scrapped the text and appended it to an NSMutableString
like so:
// contentText is the HTML text. The format is just text in <p> tags
NSData *contentData = [contentText dataUsingEncoding:NSUTF8StringEncoding];
TFHpple *htmlParser = [TFHpple hppleWithHTMLData:contentData];
NSString *htmlXpathQueryString = @"//p";
NSArray *newsNodes = [htmlParser searchWithXPathQuery:htmlXpathQueryString];
NSMutableArray *newsParagraphs = [@[] mutableCopy];
NSMutableString *newsContent = [@"" mutableCopy];
for (TFHppleElement *element in newsNodes) {
NSString *paragraphText = [[element firstChild] content];
[newsParagraphs addObject:paragraphText];
[newsContent appendFormat:@"%@\n",paragraphText];
}
// explained below (bodyView is a CTContainerView object)
self.bodyView.contentStr = newsContent;
self.bodyView.callback = ^(CGSize size) {
[self adjustScrollViewSize:size];
};
[self.bodyView buildFrames];
- (void)adjustScrollViewSize:(CGSize)contentSize {
CGRect overallSize = CGRectUnion(imageView.frame, titleText.frame);
CGRect bodyViewFr = self.bodyView.frame;
CGRect bodyViewWrapperFr = CGRectMake(bodyViewFr.origin.x,
bodyViewFr.origin.y, contentSize.width, contentSize.height+30);
overallSize = CGRectUnion(overallSize, bodyViewWrapperFr);
self.scrollView.contentSize = overallSize.size;
}
Then I used Core Text to render the text into a webview following the steps in this tutorial. Here are the other files:
CTContainerView.h
#import <UIKit/UIKit.h>
typedef void (^CompletionBlock)(CGSize size);
@interface CTContainerView : UIView
@property (nonatomic, strong) NSString *contentStr;
@property (nonatomic, strong) CompletionBlock callback;
- (void)buildFrames;
@end
CTContainerView.m
#import <CoreText/CoreText.h>
#import "CTContainerView.h"
#import "CTView.h"
const float kMargin = 10;
@implementation CTContainerView {
NSAttributedString* attString;
}
// get the required size for the final view to render
// the complete text of the body.. then pass it on
// to CTContentView
- (void)buildFrames {
// first build the attributedString with all its properties
NSString *fontName = @"29LTBukra"; // THE ARABIC FONT NAME!!!!
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)fontName, 12.0f, NULL);
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineSpacing:6];
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef, kCTFontAttributeName,
paragraphStyle, NSParagraphStyleAttributeName, nil];
attString = [[NSAttributedString alloc] initWithString:self.contentStr attributes:attrs];
// get the required final view size given attString
CGRect selfFr = self.frame;
CGRect textFr = CGRectInset(selfFr, kMargin, kMargin);
CGSize requiredSize = [self getRequiredViewSizeInViewWithSize:textFr.size];
requiredSize.height = requiredSize.height + 100;
CGRect requiredFrame = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, requiredSize.width, requiredSize.height);
// construct a CTFrameRef based on the 1. attStr and 2. calculated fr above
CGMutablePathRef path = CGPathCreateMutable(); //1
CGPathAddRect(path, NULL, requiredFrame);
CTFramesetterRef framesetter =
CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); //3
CTFrameRef frame =
CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, [attString length]), path, NULL);
// adjust size of container
selfFr.size = requiredSize;
self.frame = selfFr;
// create an empty CTContentView
CTView *ctView = [[CTView alloc] initWithFrame: CGRectMake(5, 0, requiredSize.width, requiredSize.height)];
[ctView setBackgroundColor:[UIColor whiteColor]];
[ctView setCtFrame:(__bridge id)(frame)];
[self addSubview:ctView];
CFRelease(path);
// call callback
self.callback(requiredSize);
}
- (CGSize)getRequiredViewSizeInViewWithSize:(CGSize)viewSize {
CGRect paragraphRect =
[attString boundingRectWithSize:CGSizeMake(viewSize.width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
context:nil];
return paragraphRect.size;
}
CTContentView.h
#import <UIKit/UIKit.h>
@interface CTView : UIView
@property (nonatomic, strong) id ctFrame;
@end
CTContentView.m
#import <CoreText/CoreText.h>
#import "CTView.h"
@implementation CTView
@synthesize ctFrame;
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// Flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CTFrameDraw((CTFrameRef)ctFrame, context);
}
@end