Get X and Y coordinates of a word in UITextView - iphone

I asked a developer (TwoLivesLeft, the creators of Codea) how they did syntax highlighting in their app. He replied :
#TD2 the Codea editor is implemented using a UITextView. The
highlighting is done by overlaying subviews in the appropriate
positions — usually UILabels. They are dequeued from a re-use pool,
similar to the way UITableViewCells work. During scrolling, the lines
requiring re-highlighting pull markers out of the pool and lines that
have moved off screen dump their markers back into the pool.
Can anyone explain how I would get the x and y of a certain word?

UITextView conforms to UITextInput, of which a detailed description can be found here.
Take a look at the required methods "textRangeFromPosition:toPosition:", "positionFromPosition:offset:", "positionFromPosition:inDirection:offset:", and some of the other geometric-based methods in the UITextInput Protocol. Those might provide the functionality you are looking for.
I have not actually tried to make sure these work the way you want them too, but that looks like its about what you need.
Let me know if you need any more help!
UPDATE:
Here is some sample code of how to do this. I ended up getting the "firstRectForRange:" method to work. This code basically takes the last three letters of the UITextView "textStuff" and highlights it green.
UITextView *textStuff = [[UITextView alloc] init];
textStuff.frame = CGRectMake(2.0, 200.0, 200.0, 40.0);
textStuff.text = #"how are you today?";
textStuff.textColor = [UIColor blackColor];
UITextPosition *Pos2 = [textStuff positionFromPosition: textStuff.endOfDocument offset: nil];
UITextPosition *Pos1 = [textStuff positionFromPosition: textStuff.endOfDocument offset: -3];
UITextRange *range = [textStuff textRangeFromPosition:Pos1 toPosition:Pos2];
CGRect result1 = [textStuff firstRectForRange:(UITextRange *)range ];
NSLog(#"%f, %f", result1.origin.x, result1.origin.y);
UIView *view1 = [[UIView alloc] initWithFrame:result1];
view1.backgroundColor = [UIColor colorWithRed:0.2f green:0.5f blue:0.2f alpha:0.4f];
[textStuff addSubview:view1];
Result of running this code:

#bddicken's https://stackoverflow.com/a/11487125/3549781 works like a charm. But the problem is, it doesn't work on iOS 7+ if the text contains a newline "\n". After a lot of searching I found a solution for that.
You have to ensure the layout of textView before calling firstRectForRange: by
[textView.layoutManager ensureLayoutForTextContainer:textView.textContainer];
Courtesy : UITextView firstRectForRange not working when there's new line characters in the mix
P.S : At first I added this as a comment to #bddicken's answer. As most people don't read comments I added this as an answer.

Related

iOS 7 UITextView height resize quirk

Using information I've gathered from multiple answers I found here on stackoverflow, I've been able to correctly size a UITextView's height using:
[bookQuoteTxtView sizeToFit];
[bookQuoteTxtView layoutIfNeeded];
I'm doing this because the UITextView will obviously contain different amounts of text as a result of what the user may have selected on a previous screen.
However, I'm still running into one strange problem.
It seems that when the text that gets passed into the UITextView contains a line-break, it throws the whole height thing off.
Here's the text without any line-breaks:
And here's the same text with a couple of line-breaks thrown in the middle:
As you can see (with the help of the orange & yellow background colors I added to the UITextView & ScrollView that contains it), the UITextView's height didn't resize appropriately and now the text gets cut off - all because of those linebreaks.
The code I'm using to do all this dynamic height-changing on the UITextView is:
// BookQuote TextView:
bookQuoteTxtView = [[UITextView alloc] initWithFrame:CGRectMake(5, 30, 310, 80)];
bookQuoteTxtView.backgroundColor = [UIColor orangeColor];
bookQuoteTxtView.font = [UIFont fontWithName:#"Arial" size:15];
bookQuoteTxtView.text = [NSString stringWithFormat:#"%#", bookObject.bookQuote];
[bookQuoteTxtView sizeToFit];
[bookQuoteTxtView layoutIfNeeded];
bookQuoteTxtView.editable = NO;
[scroller addSubview:bookQuoteTxtView];
// Now get the HEIGHT of the Book-Quote TextView:
CGRect textViewFrame = bookQuoteTxtView.frame;
CGFloat textViewFrameHeight = bookQuoteTxtView.contentSize.height;
textViewFrame.size.height = textViewFrameHeight;
bookQuoteTxtView.frame = textViewFrame;
So again, this works almost flawlessly for just about every string that gets passed into my UITextView box. Thus, different strings of different lengths all work, the UITextView's height adjusts automatically and everything's cool. Its just the line-breaks that throw everything off.
HAVING SAID THAT...
Its seems that line-breaks generated using "\n" in the string DO work, but line breaks that are embedded/encoded in a string that's coming in and being read from an Sqlite3 database - do NOT.
So you gotta wonder if that's where the problem lies.
Here's the code I use to read my date from the Database:
// Book Quote:
char *bookQuoteChar = (char *)sqlite3_column_text(statement, 4);
NSString *bookQuoteString;
if (bookQuoteChar == NULL) {
bookQuoteString = #"N/A";
}
else {
bookQuoteString = [[NSString alloc] initWithUTF8String:bookQuoteChar];
}
I'm thinking more and more that its the database that's causing the problem, but I'm presenting the entire picture here in its totality to make sure I'm still doing the height-readjustment stuff correctly.
Please let me know if something's jumping out at you or if there are any suggestions for fixes.
I can't really suggest much besides using a technique to set the contentSize of the UITextView.
textView.text = #"text from DB";
CGRect rect = textView.frame;
rect.size.height = textView.contentSize.height;
textView.frame = rect;
and then use any techniques that may be needed to additionally update the frame. Hope you solve the problem!

Record overlay at the same time AVFoundation iOS

I have now fully setup the ability to record video using the AVFoundation framework and this is all fine but now I am looking to add an overlay during the record (also visible on the AVCaptureVideoPreviewLayer Layer)
I can add this overlay UIView object to the VideoPreviewLayer but I am struggling how to get the same view to be on the recorded video.This UIView could contain anything from UILabels to UIImageViews.
I am not sure if this is the thing you are looking for but i guess you can use Brad Larson's GPU library,there is a class called GPUImageElement which lets you add overlays and views.Please check out the examples,especially the one called Filter showcase and scroll to something called UIElement.
Here is some sample code:
else if (filterType == GPUIMAGE_UIELEMENT)
{
GPUImageAlphaBlendFilter *blendFilter = [[GPUImageAlphaBlendFilter alloc] init];
blendFilter.mix = 1.0;
NSDate *startTime = [NSDate date];
UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 240.0f, 320.0f)];
timeLabel.font = [UIFont systemFontOfSize:17.0f];
timeLabel.text = #"Time: 0.0 s";
timeLabel.textAlignment = UITextAlignmentCenter;
timeLabel.backgroundColor = [UIColor clearColor];
timeLabel.textColor = [UIColor whiteColor];
uiElementInput = [[GPUImageUIElement alloc] initWithView:timeLabel];
[filter addTarget:blendFilter];
[uiElementInput addTarget:blendFilter];
[blendFilter addTarget:filterView];
__unsafe_unretained GPUImageUIElement *weakUIElementInput = uiElementInput;
[filter setFrameProcessingCompletionBlock:^(GPUImageOutput * filter, CMTime frameTime){
timeLabel.text = [NSString stringWithFormat:#"Time: %f s", -[startTime timeIntervalSinceNow]];
[weakUIElementInput update];
}];
}
You want to overlay UIView's, but if you don't mind using CALayers you could
add your overlay after export using AVAssetExportSession's AVVideoComposition property. It has a property, AVVideoCompositionCoreAnimationTool *animationTool which lets you add animating CALayers to your output, although I think you're out of luck if your overlay's appearance can't be described by CABasicAnimation. Your example of a display heading may be possible, although I imagine something as simple as a current time counter would not. If you can live with this restriction, the WWDC 2010 code sample 'AVEditDemo' is a good starting point.
If you need more control, you could manually render the overlay UIView onto the capture frames, using [view.layer renderInContext:contextToThenRenderToFrame] and then write these frames to file using AVAssetWriter (once you capture frames to memory you can no longer use AVCaptureMovieFileOutput).
Warning: the frames you are capturing may not arrive at a uniform rate and depend on ambient lighting and even system load. If your overlay changes at a higher rate than the capture video, then you will need to repeat frames in the second solution. This is handled for you by AVVideoComposition in the first solution.
P.S. Solution two is fiddly, but without going into details, iOS7 seems to have made this a lot easier.
you can find it in AVFoundation Programming Guide in the editing part
There is a section that deals with overlay of image. I will try to put up a sample code /project.
To figure out your problem there are two very detailed explanations on the raywenderlich tutorial site. It is a two part tutorial.
The first one is here: http://www.raywenderlich.com/13418/how-to-play-record-edit-videos-in-ios
The second one is here: http://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos
Good Luck and Hope This Helps!!

Text in UITextField moves up after editing (center while editing)

I have a strange problem. I have an UITextField in which the user should write the amount of something, so the field is called "amountField". Everything looks fine, when the user starts editing the textfield the text is in the vertical and horizontal center - that's great.
However, when the user ends editing the text moves up a little bit. I tried many things, nothing helped...
I am adding screenshots below, so you can see what is the problem.
This is what it looks like while editing the field - that's ok.
And this is how it looks when done editing - that is the problem!
Please, if anybody know what could cause this I would be very grateful! :)
Here is some of my code related to the amountField.
amountField.keyboardType = UIKeyboardTypeNumberPad;
amountField.returnKeyType = UIReturnKeyDone;
amountField.delegate = self;
[amountField setFont:[UIFont fontWithName:#"Nuptial Script LT Std" size:30]];
amountField.borderStyle = UITextBorderStyleNone;
UIImage *amountBg = [UIImage imageNamed:#"skin2_ipad_amountField.png"];
[amountField setBackground:amountBg];
amountField.rightView = nil;
//amountField.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.2];
amountField.textAlignment = UITextAlignmentCenter;
amountField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
amountField.adjustsFontSizeToFitWidth = YES;
amountLabel.textColor = UIColorFromARGB(0x313030); //Using my own macro
amountField.frame = CGRectMake(300, 480, 136, 32);
amountField.center = CGPointMake(605, 439);
PS: Those white corners are there because I set the background to white with 0.2 alpha, that's ok.
I had a similar issue that started happening on iOS 9. Basically I have a UITextField in a collection view cell. Sometimes when the user is done typing and editing ends, the text "bounces" up then down again into its correct position. Very strange and annoying glitch. Simply making this tweak fixed the issue on iOS 9 and proved to be safe on iOS 7 and 8:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
[textField layoutIfNeeded]; //Fixes iOS 9 text bounce glitch
//...other stuff
}
So...
After many hours of trying many things - I have found the problem.
In my case the problem is the font. I really don't know why, but the author of the font made the font weird (leading etc.), it has a blank space on the bottom. I don't know why, but when you are editing the text all of the text properties are ignored, but after you finish editing, they are applied.
So, if you have a similar problem, try changing the font to Arial or something similar.
For a full explanation, please consult these following links: link 1 and link 2. The solution recommended in these links can avoid you a lot of headaches and can even be applied to fix problem like text moving to the top when you start editing an UITextField (using System font or other particular fonts).
Disabling ClipsToBounds for the TextField solved it for me.
This bug happened to me when I set text & became the first responder in viewDidLoad or viewWillAppear. When I moved the becomeFirstResponder code to viewDidAppear the bug went away.
I'm struggling with this issue almost every time when the design of app is with custom font. One option is to fix the font (but this is too much work – at least for me :) ). The second option I'm using is subclassing the UITextField and overriding the editingRectForBounds: and placeholderRectForBounds: methods and correct the offset. It should work for your case too.
#implementation MyTextFieldWithFixedFontPosition
-(CGRect)editingRectForBounds:(CGRect)bounds{
return CGRectOffset([self textRectForBounds:bounds], 0, 0.5); //0.5 is just example, you can adjust to any offset you like
}
-(CGRect)placeholderRectForBounds:(CGRect)bounds{
return [self editingRectForBounds:bounds];
}
#end
I haven't tested it with leftView or rightView though, so be careful when using these :)
NOTE: this approach is "font dependant", values used for offset may vary for each font and size
There is a glitch on iOS 8.1 and below, I do not know if they will fix it later but at that time there is not an unique solution which fixes all cases, because the bug and the solutions are font's type, size dependent.
One of this solution or a combination of these solutions below can fix your problem:
Changing the font's size.
Changing the font's type.
Changing the UITextField's size.
Decompiling the font in question, modifying the font's characteristics and recompiling it (for more explanation please consult the following links: link 1 and link 2).
Otherwise this other self-sufficient solution below can fix your problem:
Swift version
import UIKit
class CustomTextField: UITextField {
...
override func textRectForBounds(bounds: CGRect) -> CGRect {
// Possible values.
return CGRectInset(bounds, CGFloat(35.0), CGFloat(0.0))
}
override func editingRectForBounds(bounds: CGRect) -> CGRect {
// Possible values.
return CGRectInset(bounds, CGFloat(35.0), CGFloat(0.0))
}
override func placeholderRectForBounds(bounds: CGRect) -> CGRect {
// Possible values.
return CGRectInset(bounds, CGFloat(35.0), CGFloat(0.0))
}
}
This solution has been tested with leftView and works like a charm.
NOTE: this approach is "font dependant", values used for CGRectInset may vary for each font and size.
I fixed this by adding height constraints to my UITextFields.
I wasn't able to change the font file, so when I solved this I saved the original UITextField's frame in a property and applied the following code:
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
textField.frame = self.usernameFrame;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
textField.frame = CGRectOffset(self.usernameFrame, 0, 1);
}
It's a bit hacky, but it gets the job done.
I had similar issues with a UITextfield embedded in a UITableViewCell. Where exactly is this code located in your project? What I believe is happening is that after you've finished editing a particular textfield, it sends itself -setNeedsDisplay and its drawRect: is subsequently called. This might explain the shift in alignment. In my particular scenario, I had to use a table view delegate method -willDisplayCell... to set the content alignment. I would have to know more about your design to possibly offer a suggestion.
One potential solution would be to use the text field delegate methods to set the content alignment.
-(void)textFieldDidEndEditing:(UITextField *)textField{
if (amountField == textField){
amountField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
}
}
Check the keyboard to change the view of the position of the pop-up if there is line of code self.view.layoutIfNeeded() Delete it.Good Luck!
This is because the BaselineOffset for the textfield got changed.
In UITextFieldDidEndEditing creating an attributed text with NSBaselineOffset: 0 and using that attributedText would fix the problem.
-(IBAction)txtFieldDidEndEditing:(UITextField *)sender {
NSDictionary *style = #{
NSBaselineOffsetAttributeName: #(0)
};
self.txtField.attributedText = [[NSAttributedString alloc] initWithString:self.txtField.text attributes:style];
}
These solution above doesn't work for me.My solution is subclass UITextField and override setText:
- (void) setText:(NSString *)text {
[super setText:text];
[self layoutIfNeeded];
}
I used this extension. Only problem was I didn't add translatesAutoresizingMaskIntoConstraints = true before I called it. Ah silly goose
func centerVertically() {
textContainerInset = UIEdgeInsets.zero
textContainer.lineFragmentPadding = 5
let fittingSize = CGSize(width: bounds.width, height:
CGFloat.greatestFiniteMagnitude)
let size = sizeThatFits(fittingSize)
let topOffset = (bounds.size.height - size.height * zoomScale) / 2
let positiveTopOffset = max(1, topOffset)
contentOffset.y = -positiveTopOffset
}

How to horizontally align underscore without repeating it?

I'm using an underscore character below each form field and related label in my view to logically seperate them. I've added the underscore in a UILabel but I'm looking for a way to repeat the _ without having to manually type it many times in the text property of the label in IB. Any idea on how to do this ?
I tried checking/unchecking "adjust to fit" but it's not working.
Thx for helping
Stephane
This is vague question, but if you want a line, I think you should rather insert generic UIView with backgroundColor that imitates the line.
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(linex, liney, thickness, length)];
line.backgroundColor = [UIColor blackColor];
[view addSubview:line];
[line release];
No matter how you'd look at this, this is much better solution than inserting undersocres.

iPhone: Grouped TableView background image problem

Hey everyone, this seems like it should be a simple one; I really hope it is. As always, thanks in advance!
All I'm trying to do is add a background image to a grouped style tableview. I'm using the following method in viewDidLoad:
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
Unfortunately, background.png seems to be drawn not only behind the cells, but also on the backgrounds of the cells and the headers as follows:
alt text http://www.freeimagehosting.net/uploads/194449ffc1.png
I know there are a few questions on this site addressing similar issues, but I'm afraid I couldn't get anything to work. How can I set the background of UITableView (the tableview style is "Grouped") to use an image? led me to add
self.tableView.opaque = NO;
self.tableView.backgroundView = nil;
to viewDidLoad and to add
cell.backgroundView = nil;
cell.opaque = NO;
in configuring my cells. Needless to say, it didn't work. Adding
cell.backgroundColor = [UIColor clearColor];
didn't work either. And sadly, that was my last idea. I'd really like to be able to do this without adding the background in interface builder, if possible. I rather like doing as much as I can programmatically. I hope asking that isn't too greedy. Thanks again!
*
*
*
EDIT:
*
*
*
I came across another approach to accomplishing this, but ran into another problem. I added the following code to viewDidLoad:
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
bgView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
[self.tableView.window addSubview:bgView];
[self.tableView addSubview:bgView];
[self.tableView sendSubviewToBack:bgView];
It looked promising, and it likely is, but unfortunately in gave me the following:
alt text http://www.freeimagehosting.net/uploads/c02dd68e20.png
It looks as though it either wasn't sent to the back and the headers somehow show through or the cells went to the back with it. I'm not at all sure. Any advice here would be appreciated as well.
Here's where I found the code for the edit:
Add UIView behind UITableView in UITableViewController code
I went through a similar path to what you describe here. I finally found an answer that worked for me on the following post:
How to set the background of a UITableView to an image?
It was two lines of code posted by user rkb. Here's the code:
self.tableView.backgroundColor = [UIColor clearColor];
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithData:imageData]];
Another solution if nothing else here is working out. In ViewDidLoad:
UIImage *background = [UIImage imageNamed:#"MyBackground.png"];
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:background];
This will place your static (doesn't stretch or move) background behind all of your grouped tableview elements, such as the headers and cells.
Using the previous responses(particularly from dana_a) this is how I got the same thing to work
self.tableView.backgroundColor = [UIColor clearColor];
self.parentViewController.view.backgroundcolor = [UIColor colorWithPatternImage:[UIImge imageNamed:#"bgtest2.png"]];
This is in my viewWillAppear: method in for my case a detail view controller with a grouped tableview.
I placed this code in my ViewDidLoad method and it worked beautifully.
self.termsTableView.backgroundColor = [UIColor clearColor];
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"metal4.png"]];
I still haven't figured out why the above doesn't work or how to modify it so that it does, but by adding the subView to the window in the App Delegate instead of the tableView here I was able to get it to work.
Instead of just getting it to function and moving on I'd like to actually learn, so I'm still curious as to where I went wrong above. As such, I'll leave this as unanswered for a time and if you can tell me my error(s) I'll give you the up vote and the green check mark. Thanks!