I can't get some CoreText text wrapping code working for me; it's just too complicated. I'm going to try and go another route, which is to split my UILabel into two.
What I'm trying to achieve is to have my text appear to wrap around my fixed sized rectangular image. It'll always be the same dimensions.
So, when the UILabel next to the image fills up exactly, it'll create another UILabel below the image.
Now, how do I calculate the text in the first UILabel and have it fit nicely in the entire width of the UILabel, without being too short or cut off at the end?
Well, this ought to work to get the substring of the master string that will fit within the desired width:
//masterString is your long string that you're looking to break apart...
NSString *tempstring = masterString;
while (someLabel.bounds.size.width < [tempString sizeWithFont:someLabelLabel.font].width) {
NSMutableArray *tempArray = [NSMutableArray arrayWithArray:[tempString componentsSeparatedByString:#" "]];
//Remove the last object, which is the last word in the string...
[tempArray removeLastObject];
//Recreate the tempString with the last word removed by piecing the objects/words back together...
tempString = #"";
for (int i=0; i < tempArray.count - 1; i++) {
tempString = [tempString stringByAppendingFormat:#"%# ", [tempArray objectAtIndex:i]];
}
//You must append the last object in tempArray without the space, or you will get an infinite loop...
tempString = [tempString stringByAppendingFormat:#"%#", [tempArray objectAtIndex:tempArray.count - 1]];
}
//Now do whatever you want with the tempString, which will fit in the width desired...
Of course, this is assuming you want the separation to occur using word wrapping. If you don't mind words themselves being cut apart (i.e. character wrap) in order to fully take up the desired width, do this instead:
NSString *tempstring = masterString;
while (someLabel.bounds.size.width < [tempString sizeWithFont:someLabelLabel.font].width) {
tempString = [tempString substringToIndex:tempString.length - 1];
}
//Now do whatever you want with the tempString, which will fit in the width desired...
In order to get the remaining piece of the string left over, do this:
NSString *restOfString = [masterString substringFromIndex:tempString.length];
Hope this helps. I have to admit that I haven't properly tested this code yet, though I've done something similar in the past...
Try below link its will help you.
If you want to create a "link" on some custom text in your label, instead of using a WebView as #Fabian Kreiser suggested, you sould use my OHAttributedLabel class (you can find it this link)
See the sample code provided on my github repository: you can use my addCustomLink:inRange: method to add a link (with a customized URL) to a range of text (range that you could determine by iterating over every occurrences of the word "iPhone" in your text very easily). Then in the delegate method on OHAttributedLabel, you can catch when the link is tapped and act accordingly to do whatever you need.
Related
I have this code to show some text in a textview from SQLite DB..
NSMutableString *combined = [NSMutableString string];
for(NSUInteger idx = 0; idx < [delegate.allSelectedVerseEnglish count]; idx++) {
[combined appendFormat:#" %d %#", idx, [delegate.allSelectedVerseEnglish objectAtIndex:idx]];
}
self.multiPageView.text = combined;
self.multiPageView.font = [UIFont fontWithName:#"Georgia" size:self.fontSize];
delegate.allSelectedVerseEnglish is the NSArray
multiPageView is the UITextView
i put the above loop function to get the Numbers according to the text,for example 1 hello 2 iPhone 3 iPad 4 mac etc etc..i just want UIButton between the text instead of 1 2 3 4 ..for example i want unbutton hello unbutton iPhone etc etc.because i need to make some touch events from it.how to do this?
Thanks in advance.
If you want to place UIButtons between some text in textview, there is no other way but to place it as a separate view just above. So you'll need to add spaces beneath those buttons, the amount of those you should calculate yourself, based on the size of your buttons.
So, if you would like yo see something like this:
Press here [UIButton] or here [Another UIButton],
your text string should look like this
Press here or here ,
So when you add the buttons on those places, it would look just like you wish.
UPDATE
Seems like we need some more code here, so here it is:
First, you'll need to calculate the size of a letter. Let's assume that it is 10 pixels height and 8 pixels.No, let's just call that letterHeight and letterWidth.Let's also assume that you want 64x10 pixels buttons. So, we will need 64/8=8 +2 spaces to out behind that button(2 to make borders around that)
So, here we go
NSMutableString *combined = [NSMutableString string];
int letterHeight = 10;
int letterWidth = 8;
for(NSString *verse in delegate.allSelectedVerseEnglish) {
[combined appendFormat:#" %#",verse];//10 spaces there
//You have to experiment with this, but idea is that your x coordinate is just proportional to the length of the line you are inserting your button in, and y is proportional to number of lines
int xCoordinate = [combined length]*letterWidth%(int)(self.multiPageView.frame.size.width);
int yCoordinate = [combined length]*letterWidth/(int)(self.multiPageView.frame.size.width)*letterHeight;
UIButton *newButton = [[UIButton alloc]initWithFrame:CGRectMake(xCoordinate,yCoordinate,64,10)];
[self.multiPageView addSubview:newButton];
}
self.multiPageView.text = combined;
I want to replace the text in UITextView text in selected range. This is my question. Here i mention what i did? and what i want to do?. I have an UITextView and entered the below text in textview.
Ask question here, i have saved the range in of the text in textview. The text range is {17, 0}. I take the NSRange in -(void) textViewDidChange:(UITextView *)textView delegate.
Now i want to replace the text question with answer and i want to replace the text here with them. The UITextView.text look like this,Ask answer them` after replaced the texts.
How can i replace the texts with the selected ranges? Can you please help me? Thanks in advance.
Since iOS 7 there is the textStorage in the textView that inherits from NSMutableAttributedString so you can use those methods:
Objective-C
[self.textView.textStorage replaceCharactersInRange:withString:];
or
[self.textView.textStorage replaceCharactersInRange:withAttributedString:];
Swift
textView.textStorage.replaceCharacters(in: range, with: string)
Well... I'm not sure to understand correctly what you're trying to do, but if your goal is to change some characters in a selected range you can follow these steps:
Get your UITextView content and put it in a NSString:
NSString *textViewContent = textView.text;
Change the characters in the range you want:
NSString *newContent = [textViewContent stringByReplacingCharactersInRange:range withString:replacement];
Replace old content with new one:
textView.text = newContent;
Anyway if you just want to replace Ask question here with Ask answer them the fastest solution is just:
textView.text = #"Ask answer them";
Well solution from top of my head..
NSArray *Dividedstring = [[self.TextView.text] componentsSeparatedByString:#" question here "]; // this will divide the string into two parts ..one before question here and second after question here.
NSString * firstpart = [Dividedstring objectAtIndex:0];
NSString * secondpart = [Dividedstring objectAtIndex:0];
self.TextView.text = [NSString stringwithFormat:#"%# answer here %#",firstpart,secondpart];
How would you go about mimicing the iPhones keypad input. So that when you click one 1 is displayed then 2 then it is 12... so on and so forth along with the ( ) -. I don't want to use the actual phone app because I'm creating a false dialer, but I want it to look and function kind of like the actual thing.
Any ideas would be greatly appreciated thanks.
EDIT:
Ok so I put in all the buttons needed but I ended up making them all individual buttons. THey are all linked including the label and this is what one button and the updater looks like.
-(IBAction)zeroButton:(id)sender{
self.enteredPhoneNumberString = [self.enteredPhoneNumberString stringByAppendingString:[NSString stringWithFormat:#"%d", "0"]];
[self updateFormattedPhoneNumberLabel];
}
-(void)updateFormattedPhoneNumberLabel {
if ([self.self.enteredPhoneNumberString length] > 3) {
NSString *firstThree = [self.enteredPhoneNumberString substringToIndex:2];
NSString *lastSet = [self.enteredPhoneNumberString substringFromIndex:2];
self.label.text = [NSString stringWithFormat:#"%#-%#", firstThree, lastSet];
}
else if ([self.self.enteredPhoneNumberString length] > 7) {
NSString *firstThree = [self.enteredPhoneNumberString substringToIndex:2];
NSString *secondThree = [self.enteredPhoneNumberString substringToIndex:2];
NSString *lastSet = [self.enteredPhoneNumberString substringFromIndex:2];
self.label.text = [NSString stringWithFormat:#"(%#) %#-%#", firstThree, secondThree, lastSet];
}
}
I had also tried it with the "" not being around the numbers being appended. Any idea why nothing is being displayed?
NEW EDIT:
I added enteredPhoneNumberString = #""; and with the numbers formatted the way you original had it displays the numbers. The main issue I'm having now is getting it so that the () and - pop up in the right spots.
I would suggest creating a grid of UIButtons that mimics the numpad, these buttons all call a method such as keyPadButtonTouchedUpInside:(id)sender and have a tag that corresponds to the number it represents.
Implementation of keyPadButtonTouchedUpInside:(id)sender may look like...
- (void)keyPadButtonTouchedUpInside:(id)sender {
UIButton *touchedButton = (UIButton *)sender;
if (touchedButton.tag <= 9) {
self.enteredPhoneNumberString = [self.enteredPhoneNumberString stringByAppendingString:[NSString stringWithFormat:#"%d", touchedButton.tag]];
[self updateFormattedPhoneNumberLabel];
} else {
// maybe some other code for pounds/stars entered on the keypad if you have these
// you will also be checking if the user hit the backspace key and trim your
// phone number string by 1
}
}
Now you need to implement updateFormattedPhoneNumberLabel
This will look at the instance NSString variable self.enteredPhoneNumberString and update a UILabel that you have in place to display the number.
updateFormattedPhoneNumberLabel might look like...
- (void)updateFormattedPhoneNumberLabel {
if ([self.self.enteredPhoneNumberString length] > 3) {
NSString *firstThree = [self.enteredPhoneNumberString subStringToIndex:2];
NSString *lastSet = [self.enteredPhoneNumberString subStringFromIndex:2];
self.formattedPhoneNumberLabel.text = [NSString stringWithFormat:#"%#-%#", firstThree, lastSet];
} else if ....
// more conditions to check for other lengths of the
// entered number and continue with the proposed formatting methods.
Hopefully that gets you down the path, there may be more efficient methods for doing this but in reality its not an intensive operation so I wouldn't worry to much about optimization unless you see some kind of entry lag which I wouldn't expect.
EDIT
I would probably update the formatting conditions so that the formatting happens in the following behavior.
1-3 numbers entered shows as "1", "12", or "123"
4-7 numbers entered shows as "123-4", "123-45", "123-456", or "123-4567"
8-10 numbers entered show as "(123) 456-78", "(123) 456-789", or "(123) 456-7890"
11 numbers entered show as "1+(234)-567-8901"
Anything more than 11 I would just show a string of numbers, unless you want to get into formatting non-us numbers. You should also play around with entering numbers in the Phone App to see how it responds if you want to mimic it completely.
If I have multi-line non-scrollable UITextView whose text is longer than can fit in the visible area, then the text just cuts off like so:
Congress shall make no law respecting
an establishment of religion, or
How would I get the text to show with an ellipsis where the text cut-off is, like so
Congress shall make no law respecting
an establishment of religion, or …
Other controls like labels and buttons have this ability.
Why not use a UILabel setting numberOfLines to something appropriate and getting that functionality for free?
The UITextView is designed to scroll when the string is larger than what the view can show. Make sure that you have set the anchoring and autoresize attributes correctly in code or your xib.
Here is an example from a blog post about how to implement your own ellipsis.
#interface NSString (TruncateToWidth)
- (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(UIFont *)font;
#end
#import "NSString+TruncateToWidth.h"
#define ellipsis #"…"
#implementation NSString (TruncateToWidth)
- (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(UIFont *)font
{
// Create copy that will be the returned result
NSMutableString *truncatedString = [[self mutableCopy] autorelease];
// Make sure string is longer than requested width
if ([self sizeWithFont:font].width > width)
{
// Accommodate for ellipsis we'll tack on the end
width -= [ellipsis sizeWithFont:font].width;
// Get range for last character in string
NSRange range = {truncatedString.length - 1, 1};
// Loop, deleting characters until string fits within width
while ([truncatedString sizeWithFont:font].width > width)
{
// Delete character at end
[truncatedString deleteCharactersInRange:range];
// Move back another character
range.location--;
}
// Append ellipsis
[truncatedString replaceCharactersInRange:range withString:ellipsis];
}
return truncatedString;
}
#end
Someone just showed me that it's actually really easy to do this with UITextView on iOS 7 and up:
UITextView *textView = [UITextView new];
textView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail;
I have an UIView containing two UILabels, in order to display a string.
The first UILabel has a fixed size, and if the string is too long and can't hold in this UILabel, I want to display the maximum characters I can in the first UILabel, and display the rest of the string in the second UILabel.
But to make this, I must know the exact part of the string displayed in the first UILabel, which is not easy because of the randomness of the string and the linebreaks.
So, is there a way to get just the text displayed in the first UILabel, without the truncated part of the string?
if ([_infoMedia.description length] > 270) {
NSRange labelLimit = [_infoMedia.description rangeOfString:#" " options:NSCaseInsensitiveSearch range:NSMakeRange(270, (_infoMedia.description.length - 270))];
_descTop.text = [_infoMedia.description substringToIndex:labelLimit.location];
_descBottom.text = [_infoMedia.description substringFromIndex:(labelLimit.location+1)];
} else {
_descTop.text = _infoMedia.description;
_descBottom.text = #"";
}
Okay that's a late answer but maybe it could help someone. The code above is approximatively the solution I used in my app.
_descTop is my first label and _descBottom is the second label. 270 is a constant equivalent to a little less than the average maximum number of characters displayed in my first label, _descTop. I calculated it by hand, trying with many different strings, maybe there's a better way to do that but this worked not bad.
If the string I want to display (_infoMedia.description) is larger than 270 characters, I isolate the first 270 characters plus the end of the next word in the string (by searching the next space), in the case where the 270 characters limit would cut the string in the middle of a word. Then I put the first part of the string in my first label, and the second part in the second label.
If not, I only put the globality of the string in the first label.
I know that's a crappy solution, but it worked and I didn't found any better way to do that.
Following code might help you in getting what you want!!
//If you want the string displayed in any given rect, use the following code..
#implementation NSString (displayedString)
//font- font of the text to be displayed
//size - Size in which we are displaying the text
-(NSString *) displayedString:(CGSize)size font:(UIFont *)font
{
NSString *written = #"";
int i = 0;
int currentWidth = 0;
NSString *nextSetOfString = #"";
while (1)
{
NSRange range;
range.location = i;
range.length = 1;
NSString *nextChar = [self substringWithRange:range];
nextSetOfString = [nextSetOfString stringByAppendingString:nextChar];
CGSize requiredSize = [nextSetOfString sizeWithFont:font constrainedToSize:CGSizeMake(NSIntegerMax, NSIntegerMax)];
currentWidth = requiredSize.width;
if(size.width >= currentWidth && size.height >= requiredSize.height)
{
written = [written stringByAppendingString:nextChar];
}
else
{
break;
}
i++;
}
return written;
}
#end