How to truncate label in cocos2dV3.0 - ios

i am trying to truncate label when text becomes large but instead it got expanded from center moving to left side.
This is my snippet.
CCLabelTTF *playerLabel = [CCLabelTTF labelWithString:[NSString stringWithFormat:#"Playerdadsadsd %d",i+1] fontName:#"Helvetica-Bold" fontSize:fontSize];
playerLabel.color = playerColor;
playerLabel.name = [NSString stringWithFormat:#"%d",1002+i];
playerLabel.position = ccp(playerSprite.position.x + playerSprite.contentSize.width + 10, yPos);
playerLabel.adjustsFontSizeToFit = YES;
[self addChild:playerLabel];

I'm not sure what are you trying to achieve, but try passing dimensions parameter to the init method:
//The label won't go out of this rectangle
CGSize rect = CGSizeMake(viewSize.width * 0.1f, viewSize.height * 0.1f);
NSString *text = [NSString stringWithFormat:#"Playerdadsadsd %d",i+1];
CCLabelTTF *playerLabel = [CCLabelTTF labelWithString: text
fontName: #"Helvetica-Bold"
fontSize: fontSize
dimensions: rect]; // <-- Note this parameter
//.. the rest of your code..

I didn't find any intrinsic solution in cocos2d-x for truncating (with or without ellipsis) a label to fit in a specified width, so I wrote a function of my own.
This is in C++, but the logic can be copied easily to Objective-C
CCLabelTTF *createTruncatedLabel(const char *text, const char *fontFace, float fontSize, int width, bool useEllipsis)
{
CCLabelTTF *ttfLabel = CCLabelTTF::create(text, fontFace, fontSize, CCSizeMake(0, 0), kCCTextAlignmentLeft);
CCSize size = ttfLabel->getContentSize();
if (size.width > width)
{
int len = strlen(text);
float pc = (float)width / (float)size.width;
int newLen = (int)((float)len * pc);
size = setTruncLabel(ttfLabel, text, newLen, useEllipsis);
if (size.width > width)
{
while (size.width > width)
{
newLen--;
size = setTruncLabel(ttfLabel, text, newLen, useEllipsis);
}
}
else
{
while (size.width < width)
{
newLen++;
size = setTruncLabel(ttfLabel, text, newLen, useEllipsis);
}
if (size.width > width)
{
newLen--;
setTruncLabel(ttfLabel, text, newLen, useEllipsis);
}
}
}
return ttfLabel;
}
CCSize setTruncLabel(CCLabelTTF *ttfLabel, const char*text, int len, bool useEllipsis)
{
char newText[256] = {0};
strncpy(newText, text, len);
if (useEllipsis)
{
strcat(newText, "...");
}
ttfLabel->setString(newText);
CCSize size = ttfLabel->getContentSize();
return size;
}

Related

The height of the weex <text> component is not accurate?

The current WeexSDK version 0.18.0,I use show similar effect on the simulator and the real machine and the text can't be fully displayed as shown below.
Also I've added the script to show how to calculate the height of the text component in source code is done. suggestSize.heightis always the height I want, but this code is only executed under iOS10. The value of totalHeight is always worse when I have more text lines than iOS10. How do I solve this?
The effect is as follows:
The source code:
- (CGSize)calculateTextHeightWithWidth:(CGFloat)aWidth
{
CGFloat totalHeight = 0;
CGSize suggestSize = CGSizeZero;
NSAttributedString * attributedStringCpy = [self ctAttributedString];
if (!attributedStringCpy) {
return CGSizeZero;
}
if (isnan(aWidth)) {
aWidth = CGFLOAT_MAX;
}
aWidth = [attributedStringCpy boundingRectWithSize:CGSizeMake(aWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading context:nil].size.width;
/* Must get ceil of aWidth. Or core text may not return correct bounds.
Maybe aWidth without ceiling triggered some critical conditions. */
aWidth = ceil(aWidth);
CTFramesetterRef ctframesetterRef = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attributedStringCpy));
suggestSize = CTFramesetterSuggestFrameSizeWithConstraints(ctframesetterRef, CFRangeMake(0, 0), NULL, CGSizeMake(aWidth, MAXFLOAT), NULL);
if (_lines == 0) {
// If not line limit use suggestSize directly.
CFRelease(ctframesetterRef);
return CGSizeMake(aWidth, suggestSize.height);
}
CGMutablePathRef path = NULL;
path = CGPathCreateMutable();
// sufficient height to draw text
CGPathAddRect(path, NULL, CGRectMake(0, 0, aWidth, suggestSize.height * 10));
CTFrameRef frameRef = NULL;
frameRef = CTFramesetterCreateFrame(ctframesetterRef, CFRangeMake(0, attributedStringCpy.length), path, NULL);
CGPathRelease(path);
CFRelease(ctframesetterRef);
if (NULL == frameRef) {
//try to protect unexpected crash.
return suggestSize;
}
CFArrayRef lines = CTFrameGetLines(frameRef);
CFIndex lineCount = CFArrayGetCount(lines);
CGFloat ascent = 0;
CGFloat descent = 0;
CGFloat leading = 0;
// height = ascent + descent + lineCount*leading
// ignore linespaing
NSUInteger actualLineCount = 0;
for (CFIndex lineIndex = 0; (!_lines|| lineIndex < _lines) && lineIndex < lineCount; lineIndex ++)
{
CTLineRef lineRef = NULL;
lineRef = (CTLineRef)CFArrayGetValueAtIndex(lines, lineIndex);
CTLineGetTypographicBounds(lineRef, &ascent, &descent, &leading);
totalHeight += ascent + descent;
actualLineCount ++;
}
totalHeight = totalHeight + actualLineCount * leading;
CFRelease(frameRef);
if (WX_SYS_VERSION_LESS_THAN(#"10.0")) {
// there is something wrong with coreText drawing text height, trying to fix this with more efficent way.
if(actualLineCount && actualLineCount < lineCount) {
suggestSize.height = suggestSize.height * actualLineCount / lineCount;
}
return CGSizeMake(aWidth, suggestSize.height);
}
return CGSizeMake(aWidth, totalHeight);
}

Dynamic CCLabelTTF font size in a specified rectangle - cocos2d

I am trying to create a text box that is specified by x, y, w, and h that can accept any string and adjust the font size to be as big as possible and still fit in the box. I have been trying several approaches, but it doesn't quite work. Here is my closest attempt:
+ (CCLabelTTF*) wrap_text :(id)not_self :(NSString *)label :(double)x :(double)y : (double)w :(double)h :(float) fontScale :(ccColor3B) color_front
{
CGSize size;
size = [[CCDirector sharedDirector] winSize];
int boxWidth = (w - x) * size.width;
int boxHeight = (h - y) * size.height;
double middleX = ((w-x)/2 + x);
double middleY = (1 - y);
middleX *= size.width;
middleY *= size.height;
//float font_size = size.height * h * fontScale;
int font_min = 5;
int font_max = 300;
int font_size = 5;
int font_size_final = -1;
int max_interations = 10;
int i;
NSString *hello = label;
UIFont *font = [UIFont fontWithName:GLOBAL_FONT size:font_size];
CGSize realSize = [hello sizeWithFont:font constrainedToSize:CGSizeMake(boxWidth, boxHeight) lineBreakMode:UILineBreakModeWordWrap ];
i = 0;
while ( true ) {
if(realSize.width < boxWidth && realSize.height < boxHeight){
//we found a good value, let's record it and try to go bigger
font_size_final = font_size;
font_min = font_size;
font_size = (font_max - font_min) / 2 + font_min;
}else if(realSize.width > boxWidth || realSize.height > boxHeight){
//too big, let's try a smaller font
font_max = font_size;
font_size = (font_max - font_min) / 2 + font_min;
}
if(font_max == font_min || i >= max_interations)
break;
font = [UIFont fontWithName:GLOBAL_FONT size:font_size];
realSize = [hello sizeWithFont:font constrainedToSize:CGSizeMake(boxWidth, boxHeight) lineBreakMode:UILineBreakModeWordWrap ];
i++;
}
G_label = [CCLabelTTF labelWithString:label fontName:GLOBAL_FONT fontSize:font_size dimensions:CGSizeMake(boxWidth, boxHeight) hAlignment:UITextAlignmentCenter];
G_label.color = color_front;
G_label.anchorPoint = ccp(0.5f, 1);
G_label.position = ccp( middleX , middleY );
[not_self addChild:G_label];
return G_label;
}
If I change boxWidth and boxHeight to 200, I get slightly better results, but I don't understand why and it's still not perfect. Can somebody tell me where I am going astray? Thanks.
*This answer is not mine: original answer is posted here - https://stackoverflow.com/a/9060833/1590951
above post gives credit to http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/
I have only made minor edits it to make it easier to test in cocos2d (tested on ancient cc2d 1.1 so if you have a different version you'll have to make the relevant edits)
You could try the following as a test to see if this will work for your needs:
NSString *fontString = #"Arial";
CGSize targetSize = CGSizeMake(300.0f, 300.0f);
int i;
int fontSizeStep = 1;
int fontSizeMin = 6;
int fontSizeMax = 28;
CCSprite *bg = [CCSprite spriteWithFile:#"Default.png"];
[bg setScaleX: targetSize.width / bg.contentSize.width];
[bg setScaleY: targetSize.height / bg.contentSize.height];
[bg setPosition:ccp(s.width / 2.0f, s.height / 2.0f)];
[bg setColor:ccc3(128, 128, 128)];
[self addChild:bg];
NSString *sampleText = #"Now the way that the book winds up is this: Tom and me found the money that the robbers hid in the cave, and it made us rich. We got six thousand dollars apiece -­ all gold. It was an awful sight of money when it was piled up. Well, Judge Thatcher he took it and put it out at interest, and it fetched us a dollar a day apiece all the year round -­ more than a body could tell what to do with. The Widow Douglas she took me for her son, and allowed she would sivilize me; but it was rough living in the house all the time, considering how dismal regular and decent the widow was in all her ways; and so when I couldn't stand it no longer I lit out. I got into my old rags and my sugar-hogshead again, and was free and satisfied. But Tom Sawyer he hunted me up and said he was going to start a band of robbers, and I might join if I would go back to the widow and be respectable. So I went back.";
// NSString *sampleText = #"Once upon a midnight dreary, while I pondered, weak and weary, Over many a quaint and curious volume of forgotten lore— While I nodded, nearly napping, suddenly there came a tapping, As of some one gently rapping, rapping at my chamber door— \"'Tis some visitor,\" I muttered, \"tapping at my chamber door— Only this and nothing more.";
UIFont *font = [UIFont fontWithName:fontString size:fontSizeMax];
/* Time to calculate the needed font size.
This for loop starts at the largest font size, and decreases by two point sizes (i=i-2)
Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */
for(i = fontSizeMax; i > fontSizeMin; i-=fontSizeStep)
{
// Set the new font size.
font = [font fontWithSize:i];
// You can log the size you're trying: NSLog(#"Trying size: %u", i);
/* This step is important: We make a constraint box
using only the fixed WIDTH of the UILabel. The height will
be checked later. */
CGSize constraintSize = CGSizeMake(targetSize.width, MAXFLOAT);
// This step checks how tall the label would be with the desired font.
CGSize labelSize = [sampleText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:CCLineBreakModeWordWrap];
/* Here is where you use the height requirement!
Set the value in the if statement to the height of your UILabel
If the label fits into your required height, it will break the loop
and use that font size. */
if(labelSize.height <= targetSize.height)
{
NSLog(#"Break on: %u", i);
break;
}
}
if(i == fontSizeMin)
{
NSLog(#"* possibly truncated text *");
}
// You can see what size the function is using by outputting: NSLog(#"Best size is: %u", i);
CCLabelTTF *label = [CCLabelTTF labelWithString:sampleText dimensions:targetSize alignment:CCTextAlignmentLeft fontName:fontString fontSize:i];
[label setPosition:ccp(s.width / 2.0f, s.height / 2.0f)];
[self addChild:label];

Calculate Font Size to Fit Frame - Core Text - NSAttributedString - iOS

I have some text which I am drawing into a fixed frame via an NSAttributedString (code below). At the moment I am hard coding the text size to 16. My question is, is there a way to calculate the best fit size for the text for the given frame ?
- (void)drawText:(CGContextRef)contextP startX:(float)x startY:(float)
y withText:(NSString *)standString
{
CGContextTranslateCTM(contextP, 0, (bottom-top)*2);
CGContextScaleCTM(contextP, 1.0, -1.0);
CGRect frameText = CGRectMake(1, 0, (right-left)*2, (bottom-top)*2);
NSMutableAttributedString * attrString = [[NSMutableAttributedString alloc] initWithString:standString];
[attrString addAttribute:NSFontAttributeName
value:[UIFont fontWithName:#"Helvetica-Bold" size:16.0]
range:NSMakeRange(0, attrString.length)];
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)(attrString));
struct CGPath * p = CGPathCreateMutable();
CGPathAddRect(p, NULL, frameText);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0,0), p, NULL);
CTFrameDraw(frame, contextP);
}
Here is a simple piece of code that will figure out the maximum font size to fit within the bounds of a frame:
UILabel *label = [[UILabel alloc] initWithFrame:frame];
label.text = #"Some text";
float largestFontSize = 12;
while ([label.text sizeWithAttributes:#{NSFontAttributeName:[UIFont systemFontOfSize:largestFontSize]}].width > modifierFrame.size.width)
{
largestFontSize--;
}
label.font = [UIFont systemFontOfSize:largestFontSize];
The only way I can see this being possible is to have a system that runs the size calculation then adjusts the size and repeats until it finds the right size.
I.e. set up a bisecting algorithm that goes between certain sizes.
i.e. run it for size 10.
Too small.
Size 20.
Too small.
Size 30.
Too big.
Size 25.
Too small.
Size 27.
Just right, use size 27.
You could even start in hundreds.
Size 100.
Too big.
Size 50.
etc...
A little trick helps to make use of sizeWithAttributes: without the need of iterating for the right result:
NSSize sampleSize = [wordString sizeWithAttributes:
#{ NSFontAttributeName: [NSFont fontWithName:fontName size:fontSize] }];
CGFloat ratio = rect.size.width / sampleSize.width;
fontSize *= ratio;
Make sure the fontSize for the sample is big enough to get good results.
The currently accepted answer talks of an algorithm, but iOS provides calculations for an NSString object.
I would use sizeWithAttributes: of the NSString class.
sizeWithAttributes:
Returns the bounding box size the receiver occupies when drawn with the given attributes.
- (CGSize)sizeWithAttributes:(NSDictionary *)attributes
Source: Apple Docs - NSString UIKit Additions Reference
EDIT Misinterpreted the question, so this answer is off the mark.
Even more easy/faster (but of course approximate) way would be this:
class func calculateOptimalFontSize(textLength:CGFloat, boundingBox:CGRect) -> CGFloat
{
let area:CGFloat = boundingBox.width * boundingBox.height
return sqrt(area / textLength)
}
We are assuming each char is N x N pixels, so we just calculate how many times N x N goes inside bounding box.
You could use sizeWithFont :
[myString sizeWithFont:[UIFont fontWithName:#"HelveticaNeue-Light" size:24]
constrainedToSize:CGSizeMake(293, 10000)] // put the size of your frame
But it is deprecated in iOS 7, so I recommend if working with string in UILabel :
[string sizeWithAttributes:#{NSFontAttributeName:[UIFont systemFontOfSize:17.0f]}];
If you are working with a rect :
CGRect textRect = [text boundingRectWithSize:mySize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:FONT}
context:nil];
CGSize size = textRect.size;
You can set the UILabel's property adjustsFontSizeToFitWidth to YES as per Apple's documentation
Here is code which will do exactly that: calculate optimal font size within some bounds. This sample is in context of UITextView subclass, so it's using its bounds as a "given frame":
func binarySearchOptimalFontSize(min: Int, max: Int) -> Int {
let middleSize = (min + max) / 2
if min > max {
return middleSize
}
let middleFont = UIFont(name: font!.fontName, size: CGFloat(middleSize))!
let attributes = [NSFontAttributeName : middleFont]
let attributedString = NSAttributedString(string: text, attributes: attributes)
let size = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]
let textSize = attributedString.boundingRect(with: size, options: options, context: nil)
if textSize.size.equalTo(bounds.size) {
return middleSize
} else if (textSize.height > bounds.size.height || textSize.width > bounds.size.width) {
return binarySearchOptimalFontSize(min: min, max: middleSize - 1)
} else {
return binarySearchOptimalFontSize(min: middleSize + 1, max: max)
}
}
I hope that helps.
Here is my solution in swift 4:
private func adjustedFontSizeOf(label: UILabel) -> CGFloat {
guard let textSize = label.text?.size(withAttributes: [.font: label.font]), textSize.width > label.bounds.width else {
return label.font.pointSize
}
let scale = label.bounds.width / textSize.width
let actualFontSize = scale * label.font.pointSize
return actualFontSize
}
I hope it helps someone.
I like the approach given by #holtwick, but found that it would sometimes overestimate what would fit. I created a tweak that seems to work well in my tests. Tip: Don't forget to test with really wide letters like "WWW" or even "௵௵௵"
func idealFontSize(for text: String, font: UIFont, width: CGFloat) -> CGFloat {
let baseFontSize = CGFloat(256)
let textSize = text.size(attributes: [NSFontAttributeName: font.withSize(baseFontSize)])
let ratio = width / textSize.width
let ballparkSize = baseFontSize * ratio
let stoppingSize = ballparkSize / CGFloat(2) // We don't want to loop forever, if we've already come down to 50% of the ballpark size give up
var idealSize = ballparkSize
while (idealSize > stoppingSize && text.size(attributes: [NSFontAttributeName: font.withSize(idealSize)]).width > width) {
// We subtract 0.5 because sometimes ballparkSize is an overestimate of a size that will fit
idealSize -= 0.5
}
return idealSize
}
Apple doesn't provides any method to find out a font size which fits the text in a given rect. Idea is to find out an optimal font size which perfectly fits the given size based on BinarySearch. Following extension tries different font sizes to converge to a perfect font size value.
import UIKit
extension UITextView {
#discardableResult func adjustFontToFit(_ rect: CGSize, minFontSize: CGFloat = 5, maxFontSize: CGFloat = 100, accuracy: CGFloat = 0.1) -> CGFloat {
// To avoid text overflow
let targetSize = CGSize(width: floor(rect.width), height: rect.height)
var minFontSize = minFontSize
var maxFontSize = maxFontSize
var fittingSize = targetSize
while maxFontSize - minFontSize > accuracy {
let midFontSize = (minFontSize + maxFontSize) / 2
font = font?.withSize(midFontSize)
fittingSize = sizeThatFits(targetSize)
if fittingSize.height <= rect.height {
minFontSize = midFontSize
} else {
maxFontSize = midFontSize
}
}
// It might be possible that while loop break with last assignment
// to `maxFontSize`, which can overflow the available height
// Using `minFontSize` will be failsafe
font = font?.withSize(minFontSize)
return minFontSize
}
}
This is the code to have dynamic font size changing by the frame width, using the logic from the other answers. The while loop might be dangerous, so please donot hesitate to submit improvements.
float fontSize = 17.0f; //initial font size
CGSize rect;
while (1) {
fontSize = fontSize+0.1;
rect = [watermarkText sizeWithAttributes:#{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]}];
if ((int)rect.width == (int)subtitle1Text.frame.size.width) {
break;
}
}
subtitle1Text.fontSize = fontSize;
Here's a method that seems to work well for iOS 9 using UITextView objects. You might have to tweet it a bit for other applications.
/*!
* Find the height of the smallest rectangle that will enclose a string using the given font.
*
* #param string The string to check.
* #param font The drawing font.
* #param width The width of the drawing area.
*
* #return The height of the rectngle enclosing the text.
*/
- (float) heightForText: (NSString *) string font: (UIFont *) font width: (float) width {
NSDictionary *fontAttributes = [NSDictionary dictionaryWithObject: font
forKey: NSFontAttributeName];
CGRect rect = [string boundingRectWithSize: CGSizeMake(width, INT_MAX)
options: NSStringDrawingUsesLineFragmentOrigin
attributes: fontAttributes
context: nil];
return rect.size.height;
}
/*!
* Find the largest font size that will allow a block of text to fit in a rectangle of the given size using the system
* font.
*
* The code is tested and optimized for UITextView objects.
*
* The font size is determined to ±0.5. Change delta in the code to get more or less precise results.
*
* #param string The string to check.
* #param size The size of the bounding rectangle.
*
* #return: The font size.
*/
- (float) maximumSystemFontSize: (NSString *) string size: (CGSize) size {
// Hack: For UITextView, the last line is clipped. Make sure it's not one we care about.
if ([string characterAtIndex: string.length - 1] != '\n') {
string = [string stringByAppendingString: #"\n"];
}
string = [string stringByAppendingString: #"M\n"];
float maxFontSize = 16.0;
float maxHeight = [self heightForText: string font: [UIFont systemFontOfSize: maxFontSize] width: size.width];
while (maxHeight < size.height) {
maxFontSize *= 2.0;
maxHeight = [self heightForText: string font: [UIFont systemFontOfSize: maxFontSize] width: size.width];
}
float minFontSize = maxFontSize/2.0;
float minHeight = [self heightForText: string font: [UIFont systemFontOfSize: minFontSize] width: size.width];
while (minHeight > size.height) {
maxFontSize = minFontSize;
minFontSize /= 2.0;
maxHeight = minHeight;
minHeight = [self heightForText: string font: [UIFont systemFontOfSize: minFontSize] width: size.width];
}
const float delta = 0.5;
while (maxFontSize - minFontSize > delta) {
float middleFontSize = (minFontSize + maxFontSize)/2.0;
float middleHeight = [self heightForText: string font: [UIFont systemFontOfSize: middleFontSize] width: size.width];
if (middleHeight < size.height) {
minFontSize = middleFontSize;
minHeight = middleHeight;
} else {
maxFontSize = middleFontSize;
maxHeight = middleHeight;
}
}
return minFontSize;
}

How to add "Copy" option to text?

I have a text in a "bubble" by fitting the text inside an image as shown below. it works fine except the text is not copyable. I need to have "copy" option so that when user tab on the text (or bubble image") "cop" options is displayed, just like in when user tab into the built in SMS Message bubble.
#import "SpeechBubbleView.h"
static UIFont* font = nil;
static UIImage* lefthandImage = nil;
static UIImage* righthandImage = nil;
const CGFloat VertPadding = 4; // additional padding around the edges
const CGFloat HorzPadding = 4;
const CGFloat TextLeftMargin = 17; // insets for the text
const CGFloat TextRightMargin = 15;
const CGFloat TextTopMargin = 10;
const CGFloat TextBottomMargin = 11;
const CGFloat MinBubbleWidth = 50; // minimum width of the bubble
const CGFloat MinBubbleHeight = 40; // minimum height of the bubble
const CGFloat WrapWidth = 200; // maximum width of text in the bubble
#implementation SpeechBubbleView
+ (void)initialize
{
if (self == [SpeechBubbleView class])
{
font = /*[*/ [UIFont systemFontOfSize:[UIFont systemFontSize]] /*retain]*/;
lefthandImage = /*[*/ [[UIImage imageNamed:/*#"BubbleLefthand"*/#"lefttest4"]
stretchableImageWithLeftCapWidth:20 topCapHeight:19] /*retain]*/;
righthandImage = /*[*/[[UIImage imageNamed:/*#"BubbleRighthand"*/#"righttest4"]
stretchableImageWithLeftCapWidth:20 topCapHeight:19] /*retain]*/;
}
}
+ (CGSize)sizeForText:(NSString*)text
{
CGSize textSize = [text sizeWithFont:font
constrainedToSize:CGSizeMake(WrapWidth, 9999)
lineBreakMode:UILineBreakModeWordWrap];
CGSize bubbleSize;
bubbleSize.width = textSize.width + TextLeftMargin + TextRightMargin;
bubbleSize.height = textSize.height + TextTopMargin + TextBottomMargin;
if (bubbleSize.width < MinBubbleWidth)
bubbleSize.width = MinBubbleWidth;
if (bubbleSize.height < MinBubbleHeight)
bubbleSize.height = MinBubbleHeight;
bubbleSize.width += HorzPadding*2;
bubbleSize.height += VertPadding*2;
return bubbleSize;
}
- (void)drawRect:(CGRect)rect
{
[self.backgroundColor setFill];
UIRectFill(rect);
CGRect bubbleRect = CGRectInset(self.bounds, VertPadding, HorzPadding);
CGRect textRect;
textRect.origin.y = bubbleRect.origin.y + TextTopMargin;
textRect.size.width = bubbleRect.size.width - TextLeftMargin - TextRightMargin;
textRect.size.height = bubbleRect.size.height - TextTopMargin - TextBottomMargin;
if (bubbleType == BubbleTypeLefthand)
{
[lefthandImage drawInRect:bubbleRect];
textRect.origin.x = bubbleRect.origin.x + TextLeftMargin;
}
else
{
[righthandImage drawInRect:bubbleRect];
textRect.origin.x = bubbleRect.origin.x + TextRightMargin;
}
[[UIColor blackColor] set];
[text drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeWordWrap];
}
- (void)setText:(NSString*)newText bubbleType:(BubbleType)newBubbleType
{
//[text release];
/**
handle local
**/
// text = [newText copy];
text = [newText copy];
bubbleType = newBubbleType;
[self setNeedsDisplay];
}
- (void)dealloc
{
//[text release];
//[super dealloc];
}
#end
If you want the system cut/copy/paste menu (or some subset thereof) without the full suite of text editability features from UITextField or UITextView, you need to present your own UIMenuController. Doing this requires:
the control to be affected by the menu can become first responder
said control (or something sensible in the responder chain above it) implements the editing methods (e.g. copy:) you want to support
you perform some event handling to present the menu controller at an appropriate time (e.g. a gesture recognizer action)
As is often the case, there's a good tutorial on NSHipster with both Swift and ObjC sample code. Kudos to #mattt, though I'd say this line needs a correction:
If you’re wondering why, oh why, this isn’t just built into UILabel, well… join the club.
"Join the club" should be replaced with "file a bug". It even sorta almost rhymes!

How to measure the max size of the largest character in a given font type and font size?

I want to cache some textures of characters of a given font type and font size, but I can't make sure of the max size the largest char may take in the whole unicode char set.
How can I calculate this size?
What you're looking for is the Font Bounding Box (or BBox). In iOS, you'll need a CGFontRef and can then use the function:
CGRect CGFontGetFontBBox (
CGFontRef font
);
This returns the font bounding box, which is the union of all glyph bounding boxes in the font. It returns the value in glyph units.
well, you may use sizeWithFont:
and check the largest (or tallest or biggest in area)
it works well for width and area, but it seems that all characters have got the same height, even dots "."
anyway, i guess that something like that should answer your question:
UIFont* aFont = [UIFont fontWithName:#"HelveticaNeue" size:15];
NSString* charsToTest = #"abcdf...xyz, ABCD...XYZ, 0123...";
float maxArea = 0;
float maxWidth = 0;
float maxHeight = 0;
NSString* largerChar;
NSString* tallerChar;
NSString* biggerChar;
for (int i = 0; i<charsToTest.length; i++) {
NSRange currentRange;
currentRange.length = 1;
currentRange.location = i;
NSString* currentCharToTest = [charsToTest substringWithRange:currentRange];
CGSize currentSize = [currentCharToTest sizeWithFont:aFont];
if (currentSize.width > maxWidth) {
maxWidth = currentSize.width;
largerChar = currentCharToTest;
NSLog(#"char:%#, new record width: %f", largerChar, maxWidth);
}
if (currentSize.height > maxHeight) {
maxHeight = currentSize.height;
tallerChar = currentCharToTest;
NSLog(#"char:%#, new record height:%f", tallerChar, maxHeight);
}
float currentArea = currentSize.height * currentSize.width;
if ( currentArea > maxArea) {
maxArea = currentArea;
biggerChar = currentCharToTest;
NSLog(#"char:%#, new area record: %f", biggerChar, maxArea);
}
}
// final resut:
NSLog(#"\n\n");
NSLog(#"char:%# --> MAX WIDTH IS: %f", largerChar, maxWidth);
NSLog(#"char:%# --> MAX HEIGHT IS: %f", tallerChar, maxHeight);
NSLog(#"char:%# --> MAX AREA IS: %f\n\n", biggerChar, maxArea);

Resources