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.
Related
I am trying to emulate the way TweetBot/NetBot animates the tabBar in after a push from the tableView of Accounts action. When the view is fully pushed, only then does the taBar animate in from the bottom. I have tried all sorts of hide/show methods and all seem to fail when it comes to the "show" part.
Does anyone have a suggestion as to how this can be done?
First of all, I presume you are not using a UITabViewController since it cannot be pushed into a UINavigationController stack, so I think you are using a standalone UITabBar embedded in a UIViewController. Is this assumption right?
Try with this code (I didn't try it).
- (void)viewDidAppear {
[super viewDidAppear];
// Calls showTabBar method after SOME_DELAY. You can also call directly [self showTabBar] if you want zero delay.
[self performSelector:#selector(showTabBar) afterDelay:SOME_DELAY];
}
- (void)showTabBar {
// Before the animation begins, your UITabBar must be outside the view controller's view frame.
CGRect tabBarFrame = CGRectMake(0,
CGRectGetHeight(self.view.bounds),
CGRectGetWidth(self.view.bounds),
CGRectGetHeight(self.tabBar.frame);
self.tabBar.frame = tabBarFrame;
// Let's start with the animation, setting a new frame for tab bar inside an animation block
[UIView animateWithDuration:ANIMATION_DURATION animations:^{
// Change origin Y. It assumes that the height of self.tabBar is right, otherwise put the height you want instead of CGRectGetHeight(self.tabBar.frame).
tabBarFrame.origin.y = CGRectGetHeight(self.view.bounds) - CGRectGetHeight(self.tabBar.frame);
self.tabBar.frame = tabBarFrame;
}];
}
I am probably doing something extremely stupid but I cannot figure out why this does not work.
I am trying to perform a simple UIView block animation but have run into trouble. I have recreated in a test project.
I have a view on a View controller, when I press the button, I create a new view and set its frame to be out of the current view (above it). I want to animate the transition so that the view currently on the screen moves downwards out of the view as the new one above it comes down to take its place.
Here is the code which is hooked up to the button,
the original view is hooked up as self.view1
- (IBAction)buttonPressed:(id)sender {
UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor blueColor];
float offScreenY = 0 - self.view1.frame.size.height;
CGRect offScreenRect = CGRectMake(0, offScreenY, self.view1.frame.size.width, self.view1.frame.size.height);
view2.frame = offScreenRect;
[self.view addSubview:view2];
float oldY = self.view1.frame.origin.y + self.view1.frame.size.height;
CGRect oldRect = CGRectMake(0, oldY, self.view1.frame.size.width, self.view1.frame.size.height);
[UIView animateWithDuration:0.5 animations:^{
self.view1.frame = oldRect;
view2.frame = CGRectMake(0, 0, self.view1.frame.size.width, self.view1.frame.size.height);
}];
}
This just animates view2 down and does not animate view 1.
If I do not add view 2 as a subview and only put view1's frame change in the animation block then view1 animates correctly.
BUT they will not work together!
Why is this?
This is a classic symptom of having autolayout turned on. If you animate frame, it works, but as soon autolayout reapplies the constraints on the view, view1 will return to its original location. By adding view2, iOS automatically reapplies autolayout constraints immediately and your view1 therefore won't move.
Bottom line, don't use autolayout and try to animate frame properties directly. Two solutions:
The easy solution is to turn off autolayout. Go to IB, select the "File inspector" and uncheck the "Use Autolayout" button:
If you want to keep autolayout on, you shouldn't be animating by changing the frame properties directly. You would animate by change the layout constraint constants. This has been answered elsewhere on S.O., but if you need guidance on that approach, let me know.
The basic idea, though, is to create an IBOutlet for your top constraint for view1 called, say, view1TopConstraint, and then in your animation block you can say
self.view1TopConstraint.constant += self.view1.frame.size.height;
[self.view layoutIfNeeded];
For this to work, though, you'd have to be careful about your other constraints on view1 (e.g., have a height constraint, have no bottom constraint or if you have one, lower its priority, etc.). This can be a hassle the first time you do it, but you'll quickly get the hang of animating by changing constraints.
But, then again, if you're using constraints, you probably shouldn't be defining view2 by its frame, but probably defining constraints for that, too.
In this case it is better for you to have a container view.
Add view1 and view2 inside this container accordingly. Container's some part will be in the screen and container's frame size will be double of the size of a view. Animate the container, so the other two views will be animated accordingly..
I have added a subview over my UITableView using:
TransparentViewController *tvc =
[[TransparentViewController alloc]
initWithNibName:#"TransparentViewController" bundle:nil];
[self.view addSubview:tvc.view];
My Nib has a UIImageView in it that has some text and a transparent background.
When I load the detailView for the table for the first time I show the subview that gives a brief explanation of the information that you can see below the text. Works really well.
What i would like to do is alter the alpha of the underlying table so that it is dimmer but not affect the alpha of the overlay subview. If i use:
[self.view setAlpha:(CGFloat)];
It dims the overlay as well. I seem to be having a mental block.
Changing the alpha affects the subviews as well. Your tvc.view is a subview of self.view, so it is naturally going to be affected.
Why don't you try this: put another view in tvc.view and send this view to this view to the back.
(UIView*) back = [[UIView alloc] initWithFrame:CGFrameMake(...)];
back.backgroundColor = [UIColor grayColor]; // choose a color that you like;
back.alpha = 0.5; // whatever works for you
[tvc.view addSubview:back];
[tvc.view sendSubviewToBack:back];
Set the size and alpha of this new view to something you like. The table view will show through it to a limited extent, which may accomplish what you are trying to do.
Since this is part of our tvc view, it will appear when you show that view and go away when you hide that view.
I'm doing a navigation based app. My rootview is a UITableView and from that I'm navigation to a UIView. For some reason the height of the UIView seems bigger than it should, meaning that the bottom of the view is not showing.
I did a really simple test using a UITextView with a button at the bottom, and only the top half of the button shows in the view when i run it in Simulator even though the height is set to 460.
Here's the code I use to navigate:
TestViewController *t = [[TestViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:t animated:YES];
In my test the .xib is just made in IB dragging a textview and a button to the UIView.
I don't have the same issue when I'm navigating to another UITableView.
What am I missing?
Make sure you have those in the IB
view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
textView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
which means that the viewControllers' view gets resized by the navigationController, the textView gets resized by the main view and the distance from the top stays the same as in your nib, and finally the distance from the bottom of the view stays the same for your button.
If you don't know how to translate these values in your IB UI, arrows is resizing and "I" is fixed distance to that side - left, top, right, bottom.
The height of the view in a navigation based app should be 480 - statusbarHeight (=20) - navigationBarHeight (=44) = 416 pixels
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.