http://stackoverflow.com/questions/7611816/multi-line-nsattributedstring-with-truncated-text/10172794#10172794

I need a UILabel subcass with multiline attributed text with support for links, bold styles, etc. I also need tail truncation with an ellipsis. None of the open source code that supports attributed text inside UILabels (TTTAttributedLabelOHAttribuedLabelTTStyledTextLabel) seem to support tail truncation for multi-line text. Is there an easy way to get this?

asked Sep 30 '11 at 14:27
John Wright
1,18631627
 

7 Answers

Hi I am the developer of OHAttributedLabel.

There is no easy way to achieve this (as explained in the associated issue I opened on the github repository of my project), because CoreText does not offer such feature.

The only way to do this would be to implement the text layout yourself using CoreText objects (CTLine, etc) instead of using the CTFrameSetter that does this for you (but w/o managing line truncation). The idea would be to build all the CTLines to lay them out (depending on the glyphs in your NSAttributedString it contains and the word wrapping policy) one after the other and manage the ellipsis at the end yourself.

I would really appreciate if someone propose a solution to do this propery as it seems a bit of work to do and you have to manage a range of special/unusual cases too (emoji cases, fonts with odd metrics and unusual glyphs, vertical alignment, take into account the size of the ellipsis itself at the end to know when to stop).

So feel free to dig around and try to implement the framing of the lines yourself it would be really appreciated!

answered Sep 30 '11 at 14:49
AliSoftware
25.9k45565
 
    
Thanks so much for the response and the confirmation that this is the case as I had thought. Is there a problem with the simple and naive solution that would calculate whether truncation is needed and then simply remove 1 or 2 characters from the attributed string and add an ellipsis in their place? – John Wright Sep 30 '11 at 15:47
    
That could work even if you will have to determine which characters to remove (at what offset does the text gets troncated — well that's the easiers part) and how much (that's more complicated) depending on the font and size at the truncation point (3 letters 'i' in plain text won't be enough but 3 'w' in bold will be too much…), and especially if the trunction happens in the middle of a change of style (font, style, size, …) too! Also the "…" ellipsis single character won't be the same size depending on the font too…, so even if this is possible, be careful with all those tricky cases – AliSoftware Sep 30 '11 at 16:28 
1  
I haven't tried this but also I noticed in the CoreText documentation on manual line breaking theCTTypesetterSuggestLineBreak function which will suggest a line break on an attributed string for a given width. This width could be calculated on the last CTLine by calculating the width of the ellipsis with the same attributed string and it seems like most of your above special cases would then be handled properly. – John Wright Oct 6 '11 at 11:19 
    
Thks for the tip, seems promising. Note: if you have a github account, don't hesitate to post a comment on the related issue (or do a fork to try some code and send a pull request then) – AliSoftware Oct 6 '11 at 12:02

Based on what I found here and over at https://groups.google.com/forum/?fromgroups=#!topic/cocoa-unbound/Qin6gjYj7XU, I came up with the following which works very well.

- (void)drawString:(CFAttributedStringRef)attString inRect:(CGRect)frameRect inContext:    (CGContextRef)context
{
CGContextSaveGState(context); // Flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0); CGFloat height = self.frame.size.height;
frameRect.origin.y = (height - frameRect.origin.y) - frameRect.size.height ; // Create a path to render text in
// don't set any line break modes, etc, just let the frame draw as many full lines as will fit
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, nil, frameRect);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attString);
CFRange fullStringRange = CFRangeMake(0, CFAttributedStringGetLength(attString));
CTFrameRef aFrame = CTFramesetterCreateFrame(framesetter, fullStringRange, framePath, NULL);
CFRelease(framePath); CFArrayRef lines = CTFrameGetLines(aFrame);
CFIndex count = CFArrayGetCount(lines);
CGPoint *origins = malloc(sizeof(CGPoint)*count);
CTFrameGetLineOrigins(aFrame, CFRangeMake(0, count), origins); // note that we only enumerate to count-1 in here-- we draw the last line separately
for (CFIndex i = 0; i < count-1; i++)
{
// draw each line in the correct position as-is
CGContextSetTextPosition(context, origins[i].x + frameRect.origin.x, origins[i].y + frameRect.origin.y);
CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i);
CTLineDraw(line, context);
} // truncate the last line before drawing it
if (count) {
CGPoint lastOrigin = origins[count-1];
CTLineRef lastLine = CFArrayGetValueAtIndex(lines, count-1); // truncation token is a CTLineRef itself
CFRange effectiveRange;
CFDictionaryRef stringAttrs = CFAttributedStringGetAttributes(attString, 0, &effectiveRange); CFAttributedStringRef truncationString = CFAttributedStringCreate(NULL, CFSTR("\u2026"), stringAttrs);
CTLineRef truncationToken = CTLineCreateWithAttributedString(truncationString);
CFRelease(truncationString); // now create the truncated line -- need to grab extra characters from the source string,
// or else the system will see the line as already fitting within the given width and
// will not truncate it. // range to cover everything from the start of lastLine to the end of the string
CFRange rng = CFRangeMake(CTLineGetStringRange(lastLine).location, 0);
rng.length = CFAttributedStringGetLength(attString) - rng.location; // substring with that range
CFAttributedStringRef longString = CFAttributedStringCreateWithSubstring(NULL, attString, rng);
// line for that string
CTLineRef longLine = CTLineCreateWithAttributedString(longString);
CFRelease(longString); CTLineRef truncated = CTLineCreateTruncatedLine(longLine, frameRect.size.width, kCTLineTruncationEnd, truncationToken);
CFRelease(longLine);
CFRelease(truncationToken); // if 'truncated' is NULL, then no truncation was required to fit it
if (truncated == NULL)
truncated = (CTLineRef)CFRetain(lastLine); // draw it at the same offset as the non-truncated version
CGContextSetTextPosition(context, lastOrigin.x + frameRect.origin.x, lastOrigin.y + frameRect.origin.y);CTLineDraw(truncated, context);CFRelease(truncated);}
free(origins);CGContextRestoreGState(context);

}

answered Feb 7 '13 at 16:30
 
    
Excellent solution! – mydogisbox Jun 24 '13 at 21:59
2  
Could you explain, which class did you subclass? – dig Jan 15 '14 at 15:13
    
@naughton this code is leaking for me... should the CTFrameRef be released also? – mga Jun 30 '14 at 20:49
    
@naughton adding CFRelease(aFrame); CFRelease(framesetter); at the end after free(origins) did the trick... no leaks! – mga Jun 30 '14 at 20:56
1  
Can we add Image to truncationToken string ? i mean attribute string with NSTextAttachment .? – Nanda Sep 8 '14 at 12:15

Maybe I'm missing something, but whats wrong with? :

NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"test"];

NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineBreakMode = NSLineBreakByTruncatingTail;
[text addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, text.length)]; label.attributedText = text;

This works perfectly and will add a ellipsis to the end.

answered Feb 18 at 15:27
Toydor
4341824
 
    
Verified. Works perfectly, iOS 8.3 here. – Matt Quiros Apr 16 at 15:13

I haven't tried this in all cases, but something like this could work for truncation:

NSAttributedString *string = self.attributedString;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity); CFAttributedStringRef attributedString = (__bridge CFTypeRef)string;
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedString);
CGPathRef path = CGPathCreateWithRect(self.bounds, NULL);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); BOOL needsTruncation = CTFrameGetVisibleStringRange(frame).length < string.length;
CFArrayRef lines = CTFrameGetLines(frame);
NSUInteger lineCount = CFArrayGetCount(lines);
CGPoint *origins = malloc(sizeof(CGPoint) * lineCount);
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); for (NSUInteger i = 0; i < lineCount; i++) {
CTLineRef line = CFArrayGetValueAtIndex(lines, i);
CGPoint point = origins[i];
CGContextSetTextPosition(context, point.x, point.y); BOOL truncate = (needsTruncation && (i == lineCount - 1));
if (!truncate) {
CTLineDraw(line, context);
}
else {
NSDictionary *attributes = [string attributesAtIndex:string.length-1 effectiveRange:NULL];
NSAttributedString *token = [[NSAttributedString alloc] initWithString:@"\u2026" attributes:attributes];
CFAttributedStringRef tokenRef = (__bridge CFAttributedStringRef)token;
CTLineRef truncationToken = CTLineCreateWithAttributedString(tokenRef);
double width = CTLineGetTypographicBounds(line, NULL, NULL, NULL) - CTLineGetTrailingWhitespaceWidth(line);
CTLineRef truncatedLine = CTLineCreateTruncatedLine(line, width-1, kCTLineTruncationEnd, truncationToken); if (truncatedLine) { CTLineDraw(truncatedLine, context); }
else { CTLineDraw(line, context); } if (truncationToken) { CFRelease(truncationToken); }
if (truncatedLine) { CFRelease(truncatedLine); }
}
} free(origins);
CGPathRelease(path);
CFRelease(frame);
CFRelease(framesetter);
answered Jan 30 '13 at 20:00
wbyoung
14.7k22035
 
    
This seems to be working, but text is drawn upside-down. To prevent this the following lines of code need to be added after CGContextSetTextMatrix(context, CGAffineTransformIdentity); :CGContextTranslateCTM(context, 0.0f, rect.size.height); CGContextScaleCTM(context, 1.0f, -1.0f); – Julia May 31 at 9:45 

You may be able to use follow code to have a more simple solution.

    // last line.
if (_limitToNumberOfLines && count == _numberOfLines-1)
{
// check if we reach end of text.
if (lineRange.location + lineRange.length < [_text length])
{
CFDictionaryRef dict = ( CFDictionaryRef)attributes;
CFAttributedStringRef truncatedString = CFAttributedStringCreate(NULL, CFSTR("\u2026"), dict); CTLineRef token = CTLineCreateWithAttributedString(truncatedString); // not possible to display all text, add tail ellipsis.
CTLineRef truncatedLine = CTLineCreateTruncatedLine(line, self.bounds.size.width - 20, kCTLineTruncationEnd, token);
CFRelease(line); line = nil;
line = truncatedLine;
}
}

I'm using MTLabel in my project and it's a really nice solution for my project.

answered Apr 16 '12 at 10:56
 

I integrated wbyoung's solution into OHAttributedLabel drawTextInRect: method if anyone is interested:

- (void)drawTextInRect:(CGRect)aRect
{
if (_attributedText)
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx); // flipping the context to draw core text
// no need to flip our typographical bounds from now on
CGContextConcatCTM(ctx, CGAffineTransformScale(CGAffineTransformMakeTranslation(0, self.bounds.size.height), 1.f, -1.f)); if (self.shadowColor)
{
CGContextSetShadowWithColor(ctx, self.shadowOffset, 0.0, self.shadowColor.CGColor);
} [self recomputeLinksInTextIfNeeded];
NSAttributedString* attributedStringToDisplay = _attributedTextWithLinks;
if (self.highlighted && self.highlightedTextColor != nil)
{
NSMutableAttributedString* mutAS = [attributedStringToDisplay mutableCopy];
[mutAS setTextColor:self.highlightedTextColor];
attributedStringToDisplay = mutAS;
(void)MRC_AUTORELEASE(mutAS);
}
if (textFrame == NULL)
{
CFAttributedStringRef cfAttrStrWithLinks = (BRIDGE_CAST CFAttributedStringRef)attributedStringToDisplay;
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(cfAttrStrWithLinks);
drawingRect = self.bounds;
if (self.centerVertically || self.extendBottomToFit)
{
CGSize sz = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0,0),NULL,CGSizeMake(drawingRect.size.width,CGFLOAT_MAX),NULL);
if (self.extendBottomToFit)
{
CGFloat delta = MAX(0.f , ceilf(sz.height - drawingRect.size.height))+ 10 /* Security margin */;
drawingRect.origin.y -= delta;
drawingRect.size.height += delta;
}
if (self.centerVertically) {
drawingRect.origin.y -= (drawingRect.size.height - sz.height)/2;
}
}
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, drawingRect);
CFRange fullStringRange = CFRangeMake(0, CFAttributedStringGetLength(cfAttrStrWithLinks));
textFrame = CTFramesetterCreateFrame(framesetter,fullStringRange, path, NULL);
CGPathRelease(path);
CFRelease(framesetter);
} // draw highlights for activeLink
if (_activeLink)
{
[self drawActiveLinkHighlightForRect:drawingRect];
} BOOL hasLinkFillColorSelector = [self.delegate respondsToSelector:@selector(attributedLabel:fillColorForLink:underlineStyle:)];
if (hasLinkFillColorSelector) {
[self drawInactiveLinkHighlightForRect:drawingRect];
} if (self.truncLastLine) {
CFArrayRef lines = CTFrameGetLines(textFrame);
CFIndex count = MIN(CFArrayGetCount(lines),floor(self.size.height/self.font.lineHeight)); CGPoint *origins = malloc(sizeof(CGPoint)*count);
CTFrameGetLineOrigins(textFrame, CFRangeMake(0, count), origins);// note that we only enumerate to count-1 in here-- we draw the last line separatelyfor(CFIndex i =0; i < count-1; i++){// draw each line in the correct position as-isCGContextSetTextPosition(ctx, origins[i].x + drawingRect.origin.x, origins[i].y + drawingRect.origin.y);CTLineRef line =(CTLineRef)CFArrayGetValueAtIndex(lines, i);CTLineDraw(line, ctx);}// truncate the last line before drawing itif(count){CGPoint lastOrigin = origins[count-1];CTLineRef lastLine =CFArrayGetValueAtIndex(lines, count-1);// truncation token is a CTLineRef itselfCFRange effectiveRange;CFDictionaryRef stringAttrs =CFAttributedStringGetAttributes((BRIDGE_CAST CFAttributedStringRef)_attributedTextWithLinks,0,&effectiveRange);CFAttributedStringRef truncationString =CFAttributedStringCreate(NULL, CFSTR("\u2026"), stringAttrs);CTLineRef truncationToken =CTLineCreateWithAttributedString(truncationString);CFRelease(truncationString);// now create the truncated line -- need to grab extra characters from the source string,// or else the system will see the line as already fitting within the given width and// will not truncate it.// range to cover everything from the start of lastLine to the end of the stringCFRange rng =CFRangeMake(CTLineGetStringRange(lastLine).location,0);
rng.length =CFAttributedStringGetLength((BRIDGE_CAST CFAttributedStringRef)_attributedTextWithLinks)- rng.location;// substring with that rangeCFAttributedStringRef longString =CFAttributedStringCreateWithSubstring(NULL,(BRIDGE_CAST CFAttributedStringRef)_attributedTextWithLinks, rng);// line for that stringCTLineRef longLine =CTLineCreateWithAttributedString(longString);CFRelease(longString);CTLineRef truncated =CTLineCreateTruncatedLine(longLine, drawingRect.size.width, kCTLineTruncationEnd, truncationToken);CFRelease(longLine);CFRelease(truncationToken);// if 'truncated' is NULL, then no truncation was required to fit itif(truncated == NULL){
truncated =(CTLineRef)CFRetain(lastLine);}// draw it at the same offset as the non-truncated versionCGContextSetTextPosition(ctx, lastOrigin.x + drawingRect.origin.x, lastOrigin.y + drawingRect.origin.y);CTLineDraw(truncated, ctx);CFRelease(truncated);}
free(origins);}else{CTFrameDraw(textFrame, ctx);}CGContextRestoreGState(ctx);}else{[super drawTextInRect:aRect];}}
answered Mar 20 '14 at 10:09
KingBabar
1,6491526
 

I used as sample MTLabel. It allows to manage line height. I needed the draw method exactly, so i just put away most stuff i did not need. This method allows me to draw multilined text in rect with tail truncation.

CGRect CTLineGetTypographicBoundsAsRect(CTLineRef line, CGPoint lineOrigin)
{
CGFloat ascent = 0;
CGFloat descent = 0;
CGFloat leading = 0;
CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
CGFloat height = ascent + descent; return CGRectMake(lineOrigin.x,
lineOrigin.y - descent,
width,
height);
}
- (void)drawText:(NSString*) text InRect:(CGRect)rect withFont:(UIFont*)aFont inContext:(CGContextRef)context { if (!text) {
return;
} BOOL _limitToNumberOfLines = YES;
int _numberOfLines = 2;
float _lineHeight = 22; //Create a CoreText font object with name and size from the UIKit one
CTFontRef font = CTFontCreateWithName((CFStringRef)aFont.fontName ,
aFont.pointSize,
NULL); //Setup the attributes dictionary with font and color
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
(id)font, (id)kCTFontAttributeName,
[UIColor lightGrayColor].CGColor, kCTForegroundColorAttributeName,
nil]; NSAttributedString *attributedString = [[[NSAttributedString alloc]
initWithString:text
attributes:attributes] autorelease]; CFRelease(font); //Create a TypeSetter object with the attributed text created earlier on
CTTypesetterRef typeSetter = CTTypesetterCreateWithAttributedString((CFAttributedStringRef)attributedString); //Start drawing from the upper side of view (the context is flipped, so we need to grab the height to do so)
CGFloat y = self.bounds.origin.y + self.bounds.size.height - rect.origin.y - aFont.ascender; BOOL shouldDrawAlong = YES;
int count = 0;
CFIndex currentIndex = 0; float _textHeight = 0; CGContextSaveGState(context); CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0); //Start drawing lines until we run out of text
while (shouldDrawAlong) { //Get CoreText to suggest a proper place to place the line break
CFIndex lineLength = CTTypesetterSuggestLineBreak(typeSetter,
currentIndex,
rect.size.width); //Create a new line with from current index to line-break index
CFRange lineRange = CFRangeMake(currentIndex, lineLength);
CTLineRef line = CTTypesetterCreateLine(typeSetter, lineRange); //Check to see if our index didn't exceed the text, and if should limit to number of lines
if (currentIndex + lineLength >= [text length])
{
shouldDrawAlong = NO;
}
else
{
if (!(_limitToNumberOfLines && count < _numberOfLines-1))
{
int i = 0;
if ([[[text substringWithRange:NSMakeRange(currentIndex, lineLength)] stringByAppendingString:@"…"] sizeWithFont:aFont].width > rect.size.width)
{
i--;
while ([[[text substringWithRange:NSMakeRange(currentIndex, lineLength + i)] stringByAppendingString:@"…"] sizeWithFont:aFont].width > rect.size.width)
{
i--;}}else{
i++;while([[[text substringWithRange:NSMakeRange(currentIndex, lineLength + i)] stringByAppendingString:@"…"] sizeWithFont:aFont].width < rect.size.width){
i++;}
i--;}
attributedString =[[[NSAttributedString alloc] initWithString:[[text substringWithRange:NSMakeRange(currentIndex, lineLength + i)] stringByAppendingString:@"…"] attributes:attributes] autorelease];CFRelease(typeSetter); typeSetter =CTTypesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);CFRelease(line);CFRange lineRange =CFRangeMake(0,0);
line =CTTypesetterCreateLine(typeSetter, lineRange); shouldDrawAlong = NO;}}CGFloat x = rect.origin.x;//Setup the line positionCGContextSetTextPosition(context, x, y);CTLineDraw(line, context); count++;CFRelease(line); y -= _lineHeight; currentIndex += lineLength;
_textHeight += _lineHeight;}CFRelease(typeSetter);CGContextRestoreGState(context);}
answered Mar 5 '12 at 16:31
mashe
7917
 
 
 
 
 
 
 

if (true&&self.lineHeights>0 && CFArrayGetCount(lines)>=2) {
NSUInteger lineCount = CFArrayGetCount(lines);
CGPoint *origins = malloc(sizeof(CGPoint) * lineCount);
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);
CTLineRef line0 = (CTLineRef)CFArrayGetValueAtIndex(lines, 0);
CTLineRef line1 = (CTLineRef)CFArrayGetValueAtIndex(lines, 1);

NSAttributedString *truncatedString = [[NSAttributedString alloc]initWithString:@"\u2026"];
CTLineRef token = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)truncatedString);
CTLineTruncationType ltt = kCTLineTruncationEnd;
CTLineRef line = CTLineCreateTruncatedLine(line1, self.width-10, ltt, token);
CGPoint point = origins[0];
CGContextSetTextPosition(context, point.x, point.y);
CTLineDraw(line0, context);
point = origins[1];
CGContextSetTextPosition(context, point.x, point.y);
CTLineDraw(line, context);
//CTFrameDraw(frame, context);
free(origins);

}

Multi-line NSAttributedString with truncated text的更多相关文章

  1. css & multi line words & ellipsis

    css & multi line words & ellipsis bug .news-card-content-title { width: 100%; height: 0.8rem ...

  2. Python使用XML操作mapnik,实现复杂标注(Multi line text symbolizer)

    test.py import mapnik stylesheet = 'world_style.xml' image = 'world_style.png' m = mapnik.Map(1200, ...

  3. Display certain line(s) from a text file in Linux.

    Purpose: Display certain line or lines from a text file, such as : Display the 1000th line from file ...

  4. Creating fields using CSOM

      When creating a field, whether you are using CAML, server-side object mode, or one of the client-s ...

  5. create feature from text file

    '''---------------------------------------------------------------------------------- Tool Name: Cre ...

  6. [转帖]Introduction to text manipulation on UNIX-based systems

    Introduction to text manipulation on UNIX-based systems https://www.ibm.com/developerworks/aix/libra ...

  7. 78k的text 文件,输出到textbox 竟然用了20几秒的原因

    开始查资料以为是io读取的,磁盘速度慢的之类的,后来一想,text 又不是几十万条数据,才那么两千行,咋回事. 原来是循环中不停的修改textbox值导致的. 总结:  比较大的运算,特别是大的循环, ...

  8. In line copy and paste to system clipboard

    On the Wiki Wiki Activity Random page Videos Photos Chat Community portal To do    Contribute  Watch ...

  9. CSU1019: Simple Line Editor

    1019: Simple Line Editor Submit Page   Summary   Time Limit: 1 Sec     Memory Limit: 128 Mb     Subm ...

随机推荐

  1. Asp.net MVC 之异常处理

    对于Asp.Net MVC 项目中,对于异常情况下,会跳转到自己定义好的页面,这时就用到了MVC中的异常过滤器(Exception Filters) (1)一旦action 方法中出现异常,异常过滤器 ...

  2. 钉钉的收费 [钉钉深圳研发团队 denny/2016.01.06/ 59888745@qq.com]

    普通用户(个人) 团队 企业 1.免费额度为每月通话100分钟.每天发DING 5次. 1.   每月通话300分钟,每天发DING   10次. 2.   群组最多可达1500人 1.   该公司所 ...

  3. smarty3与2的差异导致的小问题

    又是一天看视频~ 今天在PHP100上学习smartY教程,视频中讲到了在模板文件中直接写带有“{}”JAVASCRIPT脚本会报错,我照视频上的代码写了下来,如下: <script> f ...

  4. 鸟哥的linux私房菜学习

    cat /etc/shells 系统拥有的shellcat /etc/passwd 记录用户使用的shell按两次 tab 键可显示所有可执行的指令alias 查看所有命令的别名alias lm='l ...

  5. requirejs笔记

    1.RequireJS是一个工具库,主要用于客户端的模块管理.它可以让客户端的代码分成一个个模块.实现异步或动态加载,从而提高代码的性能和可维护性.它的模块管理遵循AMD规范(Asynchronous ...

  6. android studio新项目时提示:Plugin is too old, please update to a more recent version

    今天想写一个程序来测试一下android studo代码,但是创建好项目后,提示: Error:(1, 0) Plugin is too old, please update to a more re ...

  7. 【Android 系统开发】Android JNI/NDK (三) 之 JNIEnv 解析

    jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是 $/Android-ndk-r9d/platforms/android-1 ...

  8. tinyxml学习5

    读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...

  9. Bitmap 的bitmapdata和texture区别

    Texture:纹理类是对不同平台不同的图片资源的封装在HTML5中,资源是一个HTMLElement对象在OpenGL / WebGL中,资源是一个提交GPU后获取的纹理idTexture类封装了这 ...

  10. 更好更快更高效解析JSON说明

    现在来一个实例解析类,直接就把解析JSON到QVariant去了.唯一不足的是没有搞错误处理,具体方法也请各位自行参考json-c的发行文档,这样比较方便叙述,STL或者Boost我都没有认真接触过, ...