Take a look at the renderings first
You can specify the width of the display, the height of the display automatically increases with the number of words and it’s not fun to see that, that’s basically how IM chats work. The height of the View is automatically and dynamically increased as the font size is automatically increased
:Here's coreText. Here's a quote from Tang Qiao's blog
CoreText is the underlying technology for processing text and fonts. It works directly with Core Graphics (also known as Quartz). Quartz is a 2D graphics rendering engine capable of handling graphical displays in OSX and iOS. Quartz works directly with fonts (font) and glyphs, rendering text to the interface, and is the only module in the base library capable of handling glyphs. Therefore, CoreText needs to pass the displayed text content, position, font, and glyphs directly to Quartz for typography purposes. Compared to other UI components, CoreText provides faster typography because it interacts directly with Quartz. CoreText is very low-level, and the top UI controls (including UILabel, UITextField and UITextView) and UIWebView are all based on CoreText.
MVC concept to implement
There are three classes in model
YYGFrameParserConfig | YYGFrameParser | YYGCoreTextDat |
---|---|---|
Model
1. YYGFrameParserConfig class
Now that you want to present the content, you must know how to present the content of the content! That’s what this class does.
You need to know the width to display
@property(nonatomic, assign) CGFloat width;
You need to know the font size to display
@property(assign,nonatomic) CGFloat fontSize;
You need to know the line distance to display
@property(assign,nonatomic) CGFloat lineSpace;
You need to know the font color to display
@property(strong,nonatomic) UIColor * textColor;
The following code
@interface YYGFrameParserConfig : NSObject
/** * The width of the view */
@property(nonatomic.assign) CGFloat width;
/** * font size */
@property(assign.nonatomic) CGFloat fontSize;
/** ** line distance */
@property(assign.nonatomic) CGFloat lineSpace;
/** * font color */
@property(strong.nonatomic) UIColor * textColor;
@end-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --. M files#import "YYGFrameParserConfig.h"
@implementation YYGFrameParserConfig- (id)init
{
self= [super init];
if (self)
{
_width=200.0f;
_fontSize=16.0f;
_lineSpace=8.0f;
_textColor=RGB(108.108.108);
}
return self;
}
@endCopy the code
2. YYGFrameParser class
We all know that any information displayed on the phone screen is done by the underlying graphics rendering engine, while in UIView it is drawn on the canvas by CTFrameDraw(CTFrameRef, CGContextRef). So this class is the one that generates CTFrameRef. Generate these to display on the View! You need content! And some constraints on the content presentation, width, font size, which we did in the last class! So the following is needed:
Need to content
Need YYGFrameParserConfig
And as I said at the beginning, you can dynamically produce height through content and that’s the key so you need to return height and generated CTFrameRef
Returns the height
Return CTFrameRef
It returns two arguments. Okay, let’s just make another model so we have the next model class
Code of this class:
#import "YYGFrameParserConfig.h"
#import "YYGCoreTextData.h"
@interface YYGFrameParser : NSObject
+(YYGCoreTextData *)parseContent:(NSString *)content config:(YYGFrameParserConfig *)config;
@end.m files#import "YYGFrameParser.h"
@implementation YYGFrameParser
+(YYGCoreTextData *)parseContent:(NSString *)content config:(YYGFrameParserConfig *)config
{
NSDictionary * dictionary=[self attributesWithConfig:config];
NSAttributedString * string=[[NSAttributedString alloc]initWithString:content attributes:dictionary];
// Create CTFramesetterRef instance
CTFramesetterRef framesetter=CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
// Get the height of the region to draw
CGSize restrictSize=CGSizeMake(config.width, CGFLOAT_MAX);
CGSize coreTextSize=CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0.0), nil, restrictSize, nil);
CGFloat textHeight=coreTextSize.height;
// Generate a CTFrameRef instance
CTFrameRef frameRef=[self createFrameWithFramesetter:framesetter config:config height:textHeight];
// Save the generated CTFrameRef instance and calculated draw height to the CoreTextData instance, and return the CoreTextData instance
YYGCoreTextData *data=[[YYGCoreTextData alloc]init];
data.ctFram=frameRef;
data.height=textHeight;
CFRelease(frameRef);
CFRelease(framesetter);
returndata; } + (NSDictionary *)attributesWithConfig:(YYGFrameParserConfig *)config
{
NSMutableDictionary * dict=[NSMutableDictionary dictionary];
/ / 1
CGFloat fontSize=config.fontSize;
CTFontRef fontRef=CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);
dict[(id)kCTFontAttributeName]=(__bridge id)fontRef;
CFRelease(fontRef);
/ / 2
CGFloat lineSpace=config.lineSpace;
const CFIndex kNumberOfSetting=3;
CTParagraphStyleSetting theSettings[kNumberOfSetting]={
{kCTParagraphStyleSpecifierLineSpacingAdjustment,sizeof(CGFloat),&lineSpace},
{kCTParagraphStyleSpecifierMaximumLineSpacing,sizeof(CGFloat),&lineSpace},
{kCTParagraphStyleSpecifierMinimumLineSpacing,sizeof(CGFloat),&lineSpace}
};
CTParagraphStyleRef thePragraphRef=CTParagraphStyleCreate(theSettings, kNumberOfSetting);
dict[(id)kCTParagraphStyleAttributeName]=(__bridge id)thePragraphRef;
CFRelease(thePragraphRef);
/ / 3
UIColor * textColor=config.textColor;
dict[(id)kCTForegroundColorAttributeName]=(__bridge id)textColor.CGColor;
return dict;
}
+(CTFrameRef )createFrameWithFramesetter:(CTFramesetterRef)framesetter config:(YYGFrameParserConfig *)config height:(CGFloat)height
{
CGMutablePathRef path=CGPathCreateMutable(a);CGPathAddRect(path, NULL.CGRectMake(0.0, config.width, height));
CTFrameRef frame=CTFramesetterCreateFrame(framesetter, CFRangeMake(0.0), path, NULL);
CFRelease(path);
return frame;
}
@endCopy the code
3.YYGCoreTextData
The reason for its appearance comes from the introduction above
Store the produced CTFrameRef
@property(assign,nonatomic) CTFrameRef ctFram;
Height of dynamic generation of storage production
@property(assign,nonatomic) CGFloat height;
.m files#import "YYGCoreTextData.h"
@implementation YYGCoreTextData- (void)setCtFram:(CTFrameRef)ctFram
{
if(_ctFram! =ctFram) {if(_ctFram! =nil)
{
CFRelease(_ctFram);
}
CFRetain(ctFram);
_ctFram=ctFram;
}
}
-(void)dealloc
{
if(_ctFram! =nil)
{
CFRelease(_ctFram);
_ctFram=nil; }}@endCopy the code
View
.h files@property(strong.nonatomic) YYGCoreTextData * data; .m file - (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context=UIGraphicsGetCurrentContext(a);CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0.self.bounds.size.height);
CGContextScaleCTM(context, 1.0.1.0);
if (self.data)
{
CTFrameDraw(self.data.ctFram, context); }}Copy the code
Well, you also need to go from writing UIViewCategory
methods
Here’s a class
#import <UIKit/UIKit.h>
@interface UIView (YYGView)- (CGFloat)x; - (void)setX:(CGFloat)x; - (CGFloat)y; - (void)setY:(CGFloat)y; - (CGFloat)wide; - (void)setWide:(CGFloat)wide; - (CGFloat)height; - (void)setHeight:(CGFloat)height;
@end.m files#import "UIView+YYGView.h"
@implementation UIView (YYGView)- (CGFloat)x
{
return self.frame.origin.x; } - (void)setX:(CGFloat)x
{
self.frame=CGRectMake(x, self.y, self.wide, self.height); } - (CGFloat)y
{
return self.frame.origin.y; } - (void)setY:(CGFloat)y
{
self.frame=CGRectMake(self.x, y, self.wide, self.height); } - (CGFloat)wide
{
return self.frame.size.width; } - (void)setWide:(CGFloat)wide
{
self.frame=CGRectMake(self.x, self.y, wide, self.height); } - (CGFloat)height
{
return self.frame.size.height; } - (void)setHeight:(CGFloat)height
{
self.frame=CGRectMake(self.x, self.y, self.wide, height);
}
@endCopy the code
YYGDisplayView class
The method of Model and UIview category is to draw things on the screen, which is to play auxiliary for YYGDisplayView, auxiliary is very important!!
.m files#import "YYGDisplayView.h"
@implementation YYGDisplayView
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context=UIGraphicsGetCurrentContext(a);CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0.self.bounds.size.height);
CGContextScaleCTM(context, 1.0.1.0);
if (self.data)
{
CTFrameDraw(self.data.ctFram, context); }}@endCopy the code
The Controller is now called
YYGFrameParserConfig * config=[[YYGFrameParserConfig alloc]init];
config.textColor=[UIColor purpleColor];
config.width=self.YYGView.wide;
YYGCoreTextData * data=[YYGFrameParser parseContent:The South Korea-U.S. Joint Chiefs of Staff said Wednesday that North Korea fired two suspected Rodong ballistic missiles toward the Sea of Japan at 7:50 a.m. One of the missiles exploded shortly after launch, while the other flew over North Korea and landed in Japan's exclusive economic zone 250 kilometers off the Noka Peninsula in Akita Prefecture, a total distance of about 1,000 kilometers. Japan's Kyodo news agency analysis, north Korea's move in addition to the United States and South Korea, but also intended to restrict the Japanese government. On the other hand, the South Korean military analyzed that the North may attempt to stir up a division of public opinion in the South by launching missiles as a show of force to protest the deployment of thaAD. config:config];
self.YYGView.data=data;
self.YYGView.height=data.height;
self.YYGView.backgroundColor=[UIColor lightGrayColor];Copy the code