CoreText implements image-text mixing and click events

Source: Internet
Author: User

This example is similar to the rich text effect of Weibo. It can be used to mix text and trigger click events. The core idea of using CoreText for text-and-text mixing is to replace the original character with null characters in the position where the image needs to be placed, and implement CTRunDelegate, it is used to dynamically set the height and width of null characters (representing the image size), and set an attribute name for these null characters to distinguish them from other CTRun, this attribute can be used to identify which empty characters represent the placeholders of the image and which are common null characters when rendering the image. The key to processing click events using CoreText is to determine the position of the click is the character in the content of this article, and then determine whether the character is within the string range for processing click events.

 


// Create NSMutableAttributedString, parse all trigger click events and replace all locations where the image needs to be displayed
-(Void) buildAttribute {

Content = [[NSMutableAttributedString alloc] initWithString: originalStr];
// Create an image name
NSString * imgName = @ "smile.png ";
// Sets the CTRun callback. It is used to dynamically set the width and height of the reserved Image Location for characters that need to be replaced with the image location.
CTRunDelegateCallbacks imageCallbacks;
ImageCallbacks. version = kCTRunDelegateVersion1;
ImageCallbacks. dealloc = RunDelegateDeallocCallback;
ImageCallbacks. getAscent = RunDelegateGetAscentCallback;
ImageCallbacks. getDescent = RunDelegateGetDescentCallback;
ImageCallbacks. getWidth = RunDelegateGetWidthCallback;
// Create CTRun callback
CTRunDelegateRef runDelegate = CTRunDelegateCreate (& imageCallbacks, imgName );
// To simplify text parsing, the last character is directly considered to be the position of the image to be displayed. The original character is replaced by null characters for the position of the image to be displayed, space is used to leave a position for the image
NSMutableAttributedString * imageAttributedString = [[NSMutableAttributedString alloc] initWithString: @ ""];
// Set the image reserved character to use CTRun callback
[ImageAttributedString addattriename :( NSString *) kCTRunDelegateAttributeName value :( id) runDelegate range: NSMakeRange (0, 1)];
CFRelease (runDelegate );
// Set the reserved image character to use an imageName attribute, which is different from other characters
[ImageAttributedString addattriange: @ "imageName" value: imgName range: NSMakeRange (0, 1)];
[Content appendAttributedString: imageAttributedString];
// Set the paragraph attributes in line feed mode.
CTParagraphStyleSetting lineBreakMode;
CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;
LineBreakMode. spec = kCTParagraphStyleSpecifierLineBreakMode;
LineBreakMode. value = & lineBreak;
LineBreakMode. valueSize = sizeof (CTLineBreakMode );
CTParagraphStyleSetting settings [] = {
LineBreakMode
};
CTParagraphStyleRef style = CTParagraphStyleCreate (settings, 1 );
NSMutableDictionary * attributes = [NSMutableDictionary dictionaryWithObject :( id) style forKey :( id) kCTParagraphStyleAttributeName];
[Content addAttributes: attributes range: NSMakeRange (0, [content length])];
// The heightlight effect of the characters that need to be clicked here. This simplifies the parsing process and requires the heightlight range for hard code.
[Content addattriename :( id) kCTForegroundColorAttributeName value :( id) [[UIColor blueColor] CGColor] range: NSMakeRange (0, 10)];
}
// CTRun callback, memory destroy callback
Void RunDelegateDeallocCallback (void * refCon ){

}

// CTRun callback to get the height
CGFloat RunDelegateGetAscentCallback (void * refCon ){
NSString * imageName = (NSString *) refCon;
Return 30; // [UIImage imageNamed: imageName]. size. height;
}

CGFloat RunDelegateGetDescentCallback (void * refCon ){
Return 0;
}
// Call back CTRun to obtain the width.
CGFloat RunDelegateGetWidthCallback (void * refCon ){
NSString * imageName = (NSString *) refCon;
Return 30; // [UIImage imageNamed: imageName]. size. width;
}
-(Void) drawRect :( CGRect) rect
{
// Set all attributes of NSMutableAttributedString
[Self buildAttribute];
NSLog (@ "rect: % @", NSStringFromCGRect (rect ));
CGContextRef context = UIGraphicsGetCurrentContext ();
// Set the ctm of context to adapt to the coordinate system of core text
CGContextSaveGState (context );
CGContextSetTextMatrix (context, CGAffineTransformIdentity );
CGContextTranslateCTM (context, 0, rect. size. height );
CGContextScaleCTM (context, 1.0,-1.0 );
// Set CTFramesetter
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString (CFAttributedStringRef) content );
CGMutablePathRef path = CGPathCreateMutable ();
CGPathAddRect (path, NULL, CGRectMake (0, 0, rect. size. width, rect. size. height ));
// Create a CTFrame
_ Frame = CTFramesetterCreateFrame (framesetter, CFRangeMake (0, content. length), path, NULL );
// Draw the text content
CTFrameDraw (_ frame, context );
// Obtain the number of rows of the drawn content
CFArrayRef lines = CTFrameGetLines (_ frame );
// Obtain the origin coordinates of each line
CGPoint lineOrigins [CFArrayGetCount (lines)];
CTFrameGetLineOrigins (_ frame, CFRangeMake (0, 0), lineOrigins );
NSLog (@ "line count = % ld", CFArrayGetCount (lines ));
For (int I = 0; I <CFArrayGetCount (lines); I ++ ){
CTLineRef line = CFArrayGetValueAtIndex (lines, I );
CGFloat lineAscent;
CGFloat lineDescent;
CGFloat lineLeading;
// Obtain the width and height of each row
CTLineGetTypographicBounds (line, & lineAscent, & lineDescent, & lineLeading );
NSLog (@ "ascent = % f, descent = % f, leading = % f", lineAscent, lineDescent, lineLeading );
// Obtain each CTRun
CFArrayRef runs = CTLineGetGlyphRuns (line );
NSLog (@ "run count = % ld", CFArrayGetCount (runs ));
For (int j = 0; j <CFArrayGetCount (runs); j ++ ){
CGFloat runAscent;
CGFloat runDescent;
CGPoint lineOrigin = lineOrigins [I];
// Obtain each CTRun
CTRunRef run = CFArrayGetValueAtIndex (runs, j );
NSDictionary * attributes = (NSDictionary *) CTRunGetAttributes (run );
CGRect runRect;
// Adjust CTRun rect
RunRect. size. width = CTRunGetTypographicBounds (run, CFRangeMake (0, 0), & runAscent, & runDescent, NULL );
NSLog (@ "width = % f", runRect. size. width );

RunRect = CGRectMake (lineOrigin. x + values (line, CTRunGetStringRange (run). location, NULL), lineOrigin. y-runDescent, runRect. size. width, runAscent + runDescent );

NSString * imageName = [attributes objectForKey: @ "imageName"];
// The Image Rendering logic that specifies the position of the character to be replaced by the image.
If (imageName ){
UIImage * image = [UIImage imageNamed: imageName];
If (image ){
CGRect imageDrawRect;
ImageDrawRect. size = CGSizeMake (30, 30 );
ImageDrawRect. origin. x = runRect. origin. x + lineOrigin. x;
ImageDrawRect. origin. y = lineOrigin. y;
CGContextDrawImage (context, imageDrawRect, image. CGImage );
}
}
}
}
CGContextRestoreGState (context );
}
// Accept touch events
-(Void) touchesBegan :( NSSet *) touches withEvent :( UIEvent *) event {
// Obtain the UITouch object
UITouch * touch = [touches anyObject];
// Obtain the coordinates of the current view
CGPoint location = [touch locationInView: self];
NSLog (@ "touch: % @", NSStringFromCGPoint (location ));
// Obtain each row
CFArrayRef lines = CTFrameGetLines (_ frame );
CGPoint origins [CFArrayGetCount (lines)];
// Obtain the origin coordinates of each line
CTFrameGetLineOrigins (_ frame, CFRangeMake (0, 0), origins );
CTLineRef line = NULL;
CGPoint lineOrigin = CGPointZero;
For (int I = 0; I <CFArrayGetCount (lines); I ++)
{
CGPoint origin = origins [I];
CGPathRef path = CTFrameGetPath (_ frame );
// Obtain the entire CTFrame size
CGRect rect = CGPathGetBoundingBox (path );
NSLog (@ "origin: % @", NSStringFromCGPoint (origin ));
NSLog (@ "rect: % @", NSStringFromCGRect (rect ));
// Coordinate transformation. Convert the origin coordinates of each line to the coordinate system of uiview.
CGFloat y = rect. origin. y + rect. size. height-origin. y;
NSLog (@ "y: % f", y );
// Determine where the click is located
If (location. y <= y) & (location. x> = origin. x ))
{
Line = CFArrayGetValueAtIndex (lines, I );
LineOrigin = origin;
Break;
}
}

Location. x-= lineOrigin. x;
// Obtain the character position of the click position, which is equivalent to the number of characters clicked
CFIndex index = CTLineGetStringIndexForPosition (line, location );
NSLog (@ "index: % ld", index );
// Determine whether the character to be clicked is within the string range of the event to be clicked. Here is the string range of the event to be triggered by hard code.
If (index> = 1 & index <= 10 ){
UIAlertView * alert = [[UIAlertView alloc] initWithTitle: @ "click event" message: [originalStr failed: NSMakeRange (0, 10)] delegate: self cancelButtonTitle: @ "cancel" failed: @ "OK", nil];
[Alert show];
}

}

As follows:


 


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.