Create UIButton on substring with help of NSRange - iphone

I have some text coming from server. It may be single line or multiline text. I have to display the text on UILabel, which is no problem for me. The problem is, I have to display UIButton on finding a particular substring of the same text. For example the text is Nitish\n435-234-6543\nIndia which is being displayed as follows :
Nitish
435-234-6543
India
So, when I find 435-234-6543 I have to display UIButton on 435-234-6543.
Notes:
The text is dynamic - coming from server. Above is only an example.
UIButton will be a subview of UILabel.
I tried different ways like OHAttributedLabel, rectForLetterAtIndex and this too. But not getting success. What my idea is, to create the button when substring is found and to set the frame of button based on NSRange of substring. Is this a possibility? How can it be done? Or is there some other way to do this?
I guess it is the approach I am worried about.

-->I have tried to calcluate position but didnt get success. Seems lots of work to calcualate position. One immediate solution come to my mind is why are you not taking one or two labels and one button.
Suppose. You got dynamic string from webservice is: "Nitesh-56789-Test".
Find range of string suppose i.e. "56789".
String before starting location of that range assign to one label i.e. assign "Nitesh" to lable one.
Now add one custom button with our searched string as a text(56789).
Now make sure in main string there something after our substring or not. Here I mean after our search string "56789" still "Test" remain so assign it to third lable.
Here you have to figue out frame of all labels and button using dynamic height width calculation by using sizeWithFont method.

1) Easy solution:
Make your UILabel a UITextView and use the property dataDetectorTypes to have phone numbers as links automatically.
2) More involved solution:
There is a convenient method to determine the size any text will need to be drawn:
CGSize size = [label.text sizeWithFont:label.font
constrainedToSize:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)
lineBreakMode:UILineBreakModeWordWrap];
You could now determine which field is the phone number by splitting the string into its lines with:
NSArray *comp = [label.text componentsSeparatedByString:#"\n"];
and then checking which one is numeric. Now you would have to calculate the exact frame from the height of your size variable, maybe like this:
CGFloat positionOfNumber; // the index of your line in comp cast to CGFloat
CGFloat buffer = 10; // fiddle with this
CGFloat buttonHeight = (size.height- 2*buffer)/[comp length];
CGFloat buttonY = buffer + positionOfNumber * buttonHeight;
CGRect buttonFrame = CGRectMake(0, buttonY, label.frame.size.width, buttonHeight);

For those who want perfect solution here's the solution on how to get CGRect of a substring.

Related

How to estimate the proper height of a UITextField, to hold text of given font size

I want to display a single-line text field using UITextField and I need to know before displaying it, the proper size for its containing UICollectionViewCell. The text can be one of multiple font sizes and I need to get the right height for displaying it comfortably.
Since the text is not known in advance (it can be edited by the user), I can't use NSAttributedString's -size and -boundingRectWithSize:options:context: with anything but dummy text, in which case I can't really trust the resulting size to hold any piece of text, right?
I guess my question is: Is there a rule of thumb about typography in general, or some useful API I'm not aware of, that would allow me to determine that for displaying text at X pt, I need a text field with a height of Y px.
UITextField implements the sizeThatFits: method. So the most reliable way to get the size of your text field is to actually create one, set it up like you would set up your real text fields, and ask it for a suitable size. You don't even have to give it placeholder text, because UITextField will choose the size based on its font, not on its text.
UITextField *dummy = [[UITextField alloc] init];
dummy.font = [UIFont systemFontOfSize:20];
dummy.borderStyle = UITextBorderStyleRoundedRect;
CGFloat requiredHeight = [dummy sizeThatFits:CGSizeMake(HUGE_VALF, HUGE_VALF)].height;
// requiredHeight == 30 in my test
If your deployment target is iOS 6.0 or later, you can instead use the intrinsicContentSize property, like this:
CGFloat requiredHeight = dummy.intrinsicContentSize.height;
// requiredHeight == 30 in my test
Note that sizeThatFits: still works in iOS 6, but intrinsicContentSize is a little easier to understand.
iOS always returns a height of 30 units when the borderStyle is RoundedRect. If you want to compute the height required by a custom font, you have to change the borderStyle to any other value, compute the height, and change the borderStyle back.
textField.borderStyle = UITextBorderStyle.None;
let sizeThatFits = textField.sizeThatFits(CGSize(width:textField.bounds.width, height: CGFloat.max));
textField.bounds.height = sizeThatFits.height;
textField.borderStyle = UITextBorderStyle.RoundedRect;

how to consume string from middle and show in UILabel

I have an String that is "WAKEFIELD - TRINITYIGINY - (3.15 miles)" that need to display like this in a UILabel.That means char is consume from middle.
Note that,it should be dynamic and need to display into UITableViewCell.The strings length is not fix.It is clear that,its only string.
thanks in advance
UILabel has a property for truncation (lineBreakMode)
http://developer.apple.com/library/ios/#documentation/uikit/reference/UILabel_Class/Reference/UILabel.html
If you set it to NSLineBreakByTruncatingMiddleit will truncate in the middle.
You can yet the components from your original string using [myString componentsSeparatedByString:#" - "], then you get an array. Then, create three UILabel with different font in your cell and set lineBreakMode for the second.
If you want to create this three label with cellWidth, you probably creates your cellWidth, you put your first label to the left side of the cell, the third to the right side, and you have some place left in the middle probably. This is the place of your second label. You can calculate the size of your first and third label:
CGSize labelSize = [label.text sizeWithFont:label.font constrainedToSize:maxPossibleSizeOfTheLabel];
Use the lineBreakMode property of UILabel:
UILabel *label = ...
label.lineBreakMode = NSLineBreakByTruncatingMiddle;

How to dynamically change the position of a label according to the string length of another label?

I had two labels label1 and label2 and a tableview ,when the user click the tableview the content of the tableview is displayed in two labels.means if the tableview cell contain stack and 1 ,1 in the text-label.text. i need to display stack in the label1 and 1 in the label2 ,i have done this .but the problem is when the tableview cell content is big i.e.,instead of stack there is stackoverflow it was overlapped with label2 due to big string content
For example stack:1 is ok but when the content is stackoverflow it will appears stackoverflow1
or stackove...1 something like that.so My need is label2 must change its position according to the string length of label1.How to do this?.i hope u understand my question.
Thanks in advance.
You can get string size with the help of following code
CGSize stringSize = [myString sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE]];
Now you can get frame of the first label and then its text size as well. I hope now it will be easy for you to adjust the postion of second label. In case of any problem let me know.
Here is my code for getting number of lines of a label so that I can get the first label's height to add the second label after it.
CGSize stringSize = [myString sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE]];
int labelwidth = firstLabel.width;
int number_of_lines = stringSize.width/labelwidth;
int size = stringSize.width;
int reminder = size % labelwidth;
if(reminder != 0){
number_of_lines++;
}
// now first label height will be
rowHeight = number_of_lines*FONT_SIZE + GAP_BETWEEN_ROWS
Now you can use this rowHeigh as frame.origin.y of your second label.
Best of luck
you can set any frame you your label when you setting new text to it:
[yourLabel setFrame: CGRectMake(x, y, w, h)];
just calculate it according length of new text.
But... do you REALLY need 2 labels? If thay placed in one line and you do so only becouse of you have 2 words, you may do this much easer:
Use 1 label with widgh of all screen and set new text like this:
[yourLabel setText:[NSString stringWithFormat(#"%# %#", text1, text2)]];
Another way to achieve this if you want show on two separate labels you have to calculate the width of first label according to you text set the frame of first label and then add say 5px to the width of first label this will become x position of your next label.

Scaleable buttons in objective-c

I was wondering if its possible, and how i might do the following,
I would like to have a UIButton, a simple rounded button with one color, but i would like to have it's width scaleable based upon the UILabel that is on the inside of it.
I found somethings that talked about how it's possible to use
UItextfield
and use the .leftView and .rightView properties that it has
Could anyone give me just a quick example of how i might do this?
Thanks!
You can find the size of the NSString in the UILabel by doing something like this:
CGSize size=[uibutton.titlelabel.text sizeWithFont:[UIFont fontWithName:#"Helvetica" size:fontSize] forWidth:uibutton.titlelabel.frame.size.width lineBreakMode:UILineBreakModeCharacterWrap];
Then set the frame of the uilabel and/or uibutton using this size.width and size.height properties.
This is just an example, you will need to adjust the UIFont properties based on your label's settings or preferences.
I assume that the text of the UILabel will by dynamic, so you cannot just figure out the dimensions and add them normally?
try this:
-(void)setLabelText:(NSString*)string
{
int length = string.length;
myLabel.frame = CGRectMake(x, y, 5*length+5, height);
buttonContainingLabel.frame = CGRectMake(x, y, 25+5*length, height);
}
This method assumes a monospaced font, which you are probably not using. Still, discrepancies in character width probably won't amount to any meaningful size differential as you are not writing a novel in the button. I use the value of 5 px here as the width of a letter, but you will have to modify this to fit your text size.

String length with given font to fit UITextView

I need to move text that the user has entered into a large multi-line UITextView into a smaller (but still multi-line) UITextView*. If the user has entered more text than will display in the smaller view, I want to truncate the text so that it fits with all the (truncated) text visible. (Neither the large UITextView nor the smaller one should scroll.)
What's the best way to do this?
I can use a loop, shortening the string by a character each time, and then use NSString's sizeWithFont: constrainedToSize: lineBreakMode: to find out the height this shorter string would need, and then compare that against the height I have available in my smaller UITextView, ending the loop when the string will fit - but that seems slow and awkward. There must be a better way.
I'd like to just tell the destination UITextView to truncate its displayText member as it displays it on screen, but I've not been able to find a way to do that.
*More context on this, from a comment I made below:
I've got a landscape app. I change the layout of the view depending on the photo the user chooses. If it's a landscape photo, the caption is smaller - just a line at the bottom of the photo. If she chooses a portrait photo, then there's plenty of space I can use for the caption at the side of the photo, so the caption is bigger.
If the user changes her photo orientation from portrait to landscape, then I want to truncate the text and then allow her to edit it so that it makes sense. I could just zap it, but I'd prefer to preserve it to minimize her typing.
I wrote the following recursive method and public API to do this properly. The ugly fudge factor is the subject of this question.
#define kFudgeFactor 15.0
#define kMaxFieldHeight 9999.0
// recursive method called by the main API
-(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax
{
if ((aMax-aMin) <= 1)
{
NSString* subString = [aString substringToIndex:aMin];
return subString;
}
int mean = (aMin + aMax)/2;
NSString* subString = [aString substringToIndex:mean];
CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
if (stringSize.height <= self.frame.size.height)
return [self sizeStringToFit:aString min:mean max:aMax]; // too small
else
return [self sizeStringToFit:aString min:aMin max:mean];// too big
}
-(NSString*)sizeStringToFit:(NSString*)aString
{
CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
// if it fits, just return
if (stringSize.height < self.frame.size.height)
return aString;
// too big - call the recursive method to size it
NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]];
return smallerString;
}
This isn't actually a fix but it does provide a good starting poing for the calculation.
If you use NSString's sizeWithFont: constrainedToSize: lineBreakMode: you get a vertical height for your text. If you divide that by your font's leading height, you get the number of lines in the whole string. Dividing [NSString count] by that number gives you an approximation to number of characters per line. This assumes the string is homogeneuous and will be inaccurate if someone types (e.g.) 'iiiiiiiiiii..." as oposed to "MMMMMMMMM...".
You can also divide you bounding box by the relevent font's leading height to get the number of lines that fit within your bounding box.
Multiplying characters per line by number of lines gives you a starting point for finding text that fits.
You could calculate the margin for error in this figure by doing the same calculation for those 'iiiiii...' and "MMMMMM...'" strings.
I would suggest taking a slightly different approach and seeing if you can use a UILabel instead of the smaller UITextView.
UILabels can be setup to be multi-line like a UITextView through their numberOfLines property.
UILabels also have a lineBreakMode property and I believe that the default value of that property will do the exact truncation effect that you are looking for.
I think Jonathan was on to something about the UILabel...
So, the user finishes editing the UITextView, you get the string of text and pass it to the UILabel. You change the alpha of the UITextView to 0 and/or remove it from superview. Possibly store the untruncated full text in an ivar.
UILabels are not "editable", however you can detect a touch with a UILabel (or it's superview).
When you detect the touch on the UILabel, you simply restore the hidden UITextView and restore the string you saved.
Sometimes the SDK is a pain, but it almost always wins the fight. Many times, it is better to adjust your design to UIKit conventions