get frame of UITextField in UITableView for displaying UIPopover - iphone

I need to present a UIPopover from dynamically generated UITextFields in a UITableView. They are all tagged uniquely but when I try and use this code the popover just show up in the upper left hand corner:
[self.numbersPopover presentPopoverFromRect:[self.childSkusTable viewWithTag:aTag].frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
EDIT:
I see I am finding the frame for that tagged item but it is relavant to it's parent cell, in this case the frame of that tagged items is 0,0 for the x,y. How do I get it's position in the main window view?

Answering this just incase someone else needs it.
You have to get you UiTextFields position in the UIWindow like so:
UIView *v = [self.view viewWithTag:aTag];
CGPoint pos = [v.superview convertPoint:v.frame.origin toView:nil];
Then I just did this:
[self.numbersPopover presentPopoverFromRect:CGRectMake(pos.x, pos.y, 35, 10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
The finding positioning code form above came from this questions and answer: iPhone - Get Position of UIView within entire UIWindow

Related

presentPopoverFromRect from a button goes out of bounds

So I am using WEPopover to display a custom view controller pop up. I have a UIView in which inside it has another UIView called containerView. Inside this containerView, I have a UIButton. This is where I wanted to present my popover from. So here's what I did:
[self.popoverDialog presentPopoverFromRect:sender.frame inView:self.containerView permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
The issue is that the arrow and everything is showing from this button, but the popover goes out of self.containerView bounds. How can I make it so that the popover is displayed within the containerView bounds?
EDIT:
A picture is worth a thousand words, so here it is:
The light gray is the containerView I mentioned above. THe popover theoretically should be shown within that light gray bounds not going outside.
For the view that is contained inside the popover, go to it's view controller and set it's property contentSizeForViewInPopover. Here you can set the size so that it fits the bounds of your containerView.
OP wants to position the popover so that it only shows up in his container view. I found this bit of code in the WEPopoverController.m file
- (void)repositionPopoverFromRect:(CGRect)rect
inView:(UIView *)theView
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections {
CGRect displayArea = [self displayAreaForView:theView];
WEPopoverContainerView *containerView = (WEPopoverContainerView *)self.view;
[containerView updatePositionWithAnchorRect:rect
displayArea:displayArea
permittedArrowDirections:arrowDirections];
popoverArrowDirection = containerView.arrowDirection;
containerView.frame = [theView convertRect:containerView.frame toView:backgroundView];
}
You could possibly call this method and it might reposition your popover so that it is now inside your container viw.

how does a UIGestureRecognizer get its locationInView inside a scrollView?

We had some consultants build some code for us and the way they have it laid out is there is a UIScrollView, and a UIView inside it.
There is another UIView icon that gets added as a subview to the scrollView based on a selection in a table. When this icon gets selected a popover is presented. In the present popover code, they use the gesture's view to calculate the frame and where to present the popover.
Now I'm tasked to present the popover with a selection in the table. When the zoom is = 1, that's pretty easy. I just grab the size of the UIScrollView, calculate where I add the icon, then present the view from that icon.
When I do it at a different zoom level though, my code falls apart since I don't know exactly where I am in the scrollView. I log the consultant's gesture from their method and they'll get origin.y position's of 5000. That's why I'm asking on how the locationInView works inside a scrollView to try to figure out where I am in the yPosition to present my popover from the right place. Any thoughts? Thanks.
- (void)handleSingleTap:(UIGestureRecognizer *)sender {
id targetView = [sender view];
CGPoint point = [sender locationInView:self.scrollView];
NSLog(#"point: %f %f", point.x, point.y);

Why does UIScrollView always scrolls to bottom?

I have seen this question being addressed several times here at SO, e.g Problem with UIScrollView Content Offset, but I´m still not able to solve it.
My iphone app is basically a tab bar controller with navigation bar. I have a tableview controller made programmatically and a DetailViewController that slides in when I tap a cell in my tableview controller.
The DetailViewController is made in IB and has the following hierarchy:
top view => UIScrollView => UIView => UIImage and a UITextField.
My goal is to be able to scroll the image and text field and this works well. The problem is that my UIScrollView always gets positioned at the bottom instead at the top.
After recommendations her at SO, I have made my UIScrollView same size as the top view and instead made the UIView with the max height (1500) of my variable contents.
In ViewDidLoad I set the contentSize for the UIScrollView (as this is not accessible from IB):
- (void)viewDidLoad {
[scrollView setContentSize:CGSizeMake(320, 1500)];
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
NSLog(#"viewDidLoad: contentOffset y: %f",[scrollView contentOffset].y);
}
Specifically setting the contentOffset, I would expect my scrollView to always end up at the top. Instead it always go to the bottom. It looks to me that there is some autoscrolling beyond my control taking place after this method.
My read back of the contentOffset looks OK. It looks to me that there may be some timing related issues as the scrolling result may vary whether animation is YES or NO.
A ugly workaround I have found is by using this delegate method:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrView {
NSLog(#"Prog. scrolling ended");
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
This brings my scrollview to top, but makes it bounce down and up like a yo-yo
Another clue might be that although my instance variables for the IBOutlet are set before I push the view controller, the first time comes up with empty image and textfield:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!detailViewController) {
detailViewController = [[DayDetailViewController alloc] init];
}
// Pass dictionary for the selected event to next controller
NSDictionary *dict = [eventsDay objectAtIndex:[indexPath row]];
// This method sets values for the image and textfield outlets
[detailViewController setEventDictionary:dict];
// Push it onto the top of the navigation controller´s stack.
[[self navigationController] pushViewController:detailViewController animated:NO];
}
If I set animation to YES, and switch the order of the IBOutlet setting and pushViewController, I can avoid the emptiness upon initialization. Why?
Any help with these matters are highly appreciated, as this is really driving me nuts!
Inspired of Ponchotg´s description of a programmatically approach, I decided to skip interface builder. The result was in some way disappointing: The same problem, with the scrollview ending up in unpredictable positions (mostly at bottom), persisted.
However, I noticed that the scroll offset error was much smaller. I think this is related to the now dynamic (and generally smaller) value of ContentOffset. After some blind experimenting I ended up setting
[textView setScrollEnabled:YES];
This was previously set to NO, as the UITextView is placed inside the scrollview, which should take care of the scrolling. (In my initial question, I have erroneously said it was a UITextField, that was wrong)
With this change my problem disappeared, I was simply not able to get into the situation with scrollview appearing at bottom anymore in the simulator! (At my 3G device I have seen a slight offset appear very seldom, but this is easily fixed with scrollViewDidEndScrollingAnimation delegate described previously ).
I consider this as solved now, but would appreciate if anyone understand why this little detail messes up things?
OK! i have a question before i can give a correct answer.
Why are you using a UIView inside the Scrollview?
You can always only put your UIImageView and UITextField inside the UIScrollView without the UIView
and set the contentSize dynamically depending on the size of the text.
to give you an example how i do it:
int contSize = 0;
imageView.frame = CGRectMake(10, 0, 300, 190);
imageView.image = [UIImage imageNamed:#"yourimage"];
contSize = 190 //or add extra space if you dont want your image and your text to be so close
[textField setScrollEnabled:NO];
textField.font = [UIFont systemFontOfSize:15];
textField.textColor = [UIColor grayColor];
textField.text = #"YOUR TEXT";
[textField setEditable:NO];
textField.frame = CGRectMake(5, contSize, 310, 34);
CGRect frameText = textField.frame;
frameText.size.height = textField.contentSize.height;
textField.frame = frameText;
contSize += (textField.contentSize.height);
[scrollView setScrollEnabled:YES];
[scrolView setContentSize:CGSizeMake(320, contSize)];
In the above example I first create an int to keep track of the ysize of my view then Give settings and the image to my UIImageView and add that number to my int then i give settings and text to my UITextField and then i calculate the size of my text depending on how long is my text and the size of my font, then add that to my int and finally assign the contentSize of my ScrollView to match my int.
That way the size of your scrollview will always match your view, and the scrollView will always be at top.
But if you don't want to do all this, you can allways just:
[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
at the end of the code where you set your image and your text, and the NOto avoid the bouncing.
Hope this helps.

UIPopoverController: Why my popover doesn't appears where i want to?

Simple:
A view, i present a UIPopoverController in a CGRect using presentPopoverFromRect...
and neither the arrow or the popover frame appear even near to the coordinates i asked for in the rect i passed into.
Any clues?
I've been trying to figure out this by myself but am giving up. Here is the code:
if(!myContentController){
myContentController = [[MyContentController alloc] initWithNibName:myNibName bundle:[NSBundle mainBundle]];
// This works pretty well. actually when i show the popover
// i see everything inside as it's supposed to.
}
if(!popover){
popover = [[UIPopoverController alloc] initWithContentViewController:myContentController];
}
else{
[popover setContentController:myContentController];
}
popover.delegate = self;
CGPoint touchPointInView = [self touchPoint];//This is working fine too.I've been checking with NSLog.
popover.ContentSize = myPopoverSize;//In this case {320,480}
[popover presentPopoverFromRect:CGRectMake(touchPoint.x,touchPoint.y,myPopoverSize.width,myPopverSize.height)
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
What happens next? the popover doesn't shows where it should be. If i pass {0,0} it shows in the middle of the screen as if the view size were (768,512). I checked all the view dimensions and they are all ok, frame,bounds, etc... . Does anyone knows what am i doing wrong?
The CGRect you give to presentPopoverFromRect is the rect that it will display the popover next to (not in). Depending on the location of the rect, the popover will appear on an appropriate side of the specified rect.
If you want the popover to appear at a specific point, give it a rect with the origin as the point and the size as 1,1. So the CGRectMake in the presentPopoverFromRect line should be:
CGRectMake(touchPoint.x,touchPoint.y,1,1)
Also make sure that the touchPoint is relative to the inView (self.view in your case).
By the way, there are a few other errors in the code (probably just typos in the question):
setContentController should be setContentViewController
popover.ContentSize should be popover.popoverContentSize
myPopverSize.height should be myPopoverSize.height (but this will be replaced by 1)
In my case the reason of this problem was following. It is also possible, that your view is a tableView. So, when you scroll it and try to show UIPopover in a rect in that tableView, it may not be shown. I used this:
[_popoverController presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

iOS -- how do you control the size of a modal view controller?

I am presenting a modal view controller. If it matters, it is scrolling up from the bottom. How can I control what portion of the screen it occupies?
EDIT: I have the following in the modal view controller. It's not helping.
- (void)viewDidLoad {
TestResultView *trv = [[TestResultView alloc]initWithTest: [Model m].currentTest];
self.view = trv;
trv.frame = CGRectMake(0, 320, 320, 160);
[trv release];
[super viewDidLoad];
}
You can modify the frame of the view controller, but if you're using UIViewController's -presentModalViewController:animated: method, the view behind will be unloaded once your modal view is finished animating onto the screen (This assumes you're on an iPhone) and you'll see a white screen where your background view should be. iOS assumes that your modal view controller will be a full-screen view controller, and dumps the other view to save memory.
If you really want to show a view over part of the screen, you should instead add the UIView (no UIViewController) to your current UIViewController's view as a subview, and then animate it onscreen yourself. I think something like this would work in your UIViewController class that will present the view:
// Add the view as a subview and position it offscreen just below the current view
UIView *myHalfView = [[UIView alloc] initWithFrame:someAppropriateFrame];
[self.view addSubview:myHalfView];
CGRect offScreenFrame = myHalfView.bounds;
offScreenFrame.origin = CGPointMake(0.0, CGRectGetMaxY(self.view.frame));
// Now animate the view upwards
[UIView beginAnimations:nil context:nil];
// Move the view upwards the height of your sliding view so it's entirely onscreen
myHalfView.center = CGPointMake(myHalfView.center.x, myHalfView.center.y - myHalfView.bounds.size.height);
[UIView commitAnimations];
[myHalfView release];
For bonus points, you could fade the view in by setting
myHalfView.alpha = 0.0;
before the UIView animation block, and setting
myHalfView.alpha = 1.0;
inside the block after animating the center property.
When you're done, you can do something similar but in reverse to slide the view offscreen. You can add an animationDidStop selector to the UIView animation block to be notified when the view has slid off screen so that you can remove it from the view hierarchy.
From an aesthetic point of view, you should also be careful how you do this since having a view slide up is a standard behavior, and if your view looks like a normal view but stops halfway, users may feel (even briefly) that the app has frozen. They'll figure it out, but it will leave a bad feeling about your app if not handled carefully. Mainly, I would avoid using standard full-screen cues like including a UINavigationController at the top of your view to help users understand what's going on. Half-sheets tend to be UIActionSheets on the iPhone, so think in that direction.
That is nice, the above accepted answer explains a nice hack to present subViews which feel like ModalViews, but what if it is an iPad, and i can indeed give it a modalViewController which doesnt cover the entire screen.
In case of iPads, I dont think the underneath view will be unloaded. ( because there are options where we can present the modalView on iPads, which dont cover the entire screen )
ModalViewController in the end is a controller itself, and like any other controller has a root view, whose properties can be editted, if we can get hold of it.
Here is what will give you a custom frame of the ModalView :
MyViewController *viewController = [[MyViewController alloc] init];
viewConroller.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:viewController animated:YES];
//superView of viewController's view is modalViewController's view, which we were after
viewController.view.superview.frame = CGRectMake(x,y,w,h);
//x y w h - can have desired values.
I would add to #dsaw's answer that the superview of the modal view does not seem to rotate its coordinate system in landscape mode. Here is the code that I used in my own app:
MyViewController* modalVC = [[MyViewController alloc] init];
modalVC.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:modalVC animated:NO];
CGRect r = CGRectMake(self.view.bounds.size.width/2 - 236,
self.view.bounds.size.height/2 - 130,
472, 260);
r = [self.view convertRect:r toView:modalVC.view.superview.superview];
modalVC.view.superview.frame = r;
While the superview may not rotate itself with the iPad, it does seem to do the right thing and keep the modal view centered if I rotate the iPad after showing the modal view.