iOS - Insert subview between the background and toolbar of another view - ios

Pardon my ugly illustration below:
I have a view controller A that has a toolbar T at the bottom; toolbar is part of controller A, created by choosing "Opaque Toolbar" as "Bottom Bar" in the Attributes Inspector of view controller A. I'd like a banner B to slide up from the top of toolbar T, stay there for 2 seconds then disappear. Banner B is not within the view hierarchy of controller A. The issue right now is that the banner covers the toolbar during the sliding up process; I'd like the notification banner to emerge from the top of the toolbar, initially completely covered by the toolbar, instead of covering the toolbar.
Changing the layer index of the banner doesn't work, because the banner is not within the layer system of the view below it.
Here's my code snippet that adds the banner and animates it:
[containerView addSubview:innerView];
// Animate In
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{
[innerView setFrame:target];
} completion:^(BOOL finished) {
if (finished) {
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[innerView addGestureRecognizer:tapGestureRecognizer];
}
}];
Is there a way to insert the banner so that it appears above the background of controller A but below the toolbar of the controller?

Maybe you can try :
[self.view bringSubviewToFront : toolbarView]; //Top level
[self.view insertSubview:bannerView belowSubview: toolBarView]; //below your toolbar

I assume your containerView is the view of a UINavigationController, as you cannot add a toolbar in the attributes inspector for UIViewController. I would suggest you just add the banner to self.view
[self.view addSubview:innerView];
If you feel like this will not work. You should probably subclass UINavigationController and add the subview of it.
[self.view insertSubview:bannerView belowSubview: self.toolbar]; //toolbar is a property of UINavigationController
I suppose it's possible to say something like:
[self.navigationController.view insertSubview:bannerView belowSubview: self.navigationController.toolBarView];
Generally you want view controllers to manager their own view hierarchy. So it is better to avoid the third options.

Related

How to disable background view with dark transparent color?

I created animation for a uiview that slides from the bottom of the screen, but i want after the view slides on to the screen to make the bg view disabled and with dark bg like this:
How can i do this? Also when i tap the dark transparent view i want it to slide out and to make the bg view enabled.
this is how I do the sliding animation:
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
} else if (buttonIndex == 1) {
self.slidingView.hidden = NO;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
self.slidingView.frame = CGRectMake(0,0,320,20);
self.view.frame = CGRectMake(0,0,320,460);
[UIView commitAnimations];
self.view.userInteractionEnabled = NO;
}
}
Thanksss
I did a similar thing on a recent project.
Instead of adding only one view which is the view that contains the picker, add a parent view to it.
So what you will be adding to your view controller is a view that will be the size of your screen with a transparent black background and then add to it a subview the view with your picker with your custom animation.
Another way to do this is to have a view in your view controller that is initially hidden and when you show your picker view you show it.
I can help you better if you can share your code.
Edit:
-add a view in your view controller with the same width and height, with leading, top, trailing and bottom constraints.
-have an outlet for this view (ex:backgroundView)
-in your viewDidLoad: add the following line:
self.backgroundView.hidden=YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(yourcodeToCloseTheView)];
singleTap.numberOfTapsRequired = 1;
[self.backgroundView addGestureRecognizer:singleTap];
-and in your actionSheet:clickedButtonAtIndex: add this line:
self.backgroundView.hidden=NO;
Just make sure that the backgroundView is behind your pickerView in IB.
Hope that helps

Adding a new view on top of an existing view

I want to add a view called anotherView on top of self.view. But I don't want anotherView to be a subview. Is this possible?
I want anotherView to be at the top of the page and push the contents of self.view down accordingly (without having to change the y or height values.
I have the following and it doesn't work:
UIView *anotherView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, self.view.frame.size.width, 80)];
anotherView.backgroundColor = [UIColor yellowColor];
[self.view insertSubview:anotherView aboveSubview:self.view];
The box is simply on top of the existing view.
Any visible view is subview of some other view or window.
But you can add anotherView to
self.view.superview
or even
self.view.window
or create new UIWindow object and add your subview to this window
Have you tried to present anotherView modally? That way you can make it to appear on top of everything being a completly new view controller. Ex:
[self presentModalViewController:anotherView animated:YES];
assuming of course anotherView is a subclass of UIViewController and has its own View property. Because if anotherView is just subclass of UIView then you can't present it without being a subview of the current View Controller.
EDIT:
Oh yes, you can just pass a nil to the completion block:
[self presentViewController:anotherView animated:YES completion:nil];

Is it correct to move the navigation bar frame?

I have a navigation bar based ipad app.
At some point I want to push another view controller into the views controller hierarchy. Then, when the users tabs some button I want to show a leftMenu controller. To do so I have two views:
A content view which has all the content
And a not visible view which is the leftMenu. This one is under the content view.
So when the user presses the button, what Im doing right now is moving the content view and the navigation bar to the right to make the leftMenu visible:
self.navigationController.navigationBar.frame = CGRectMake(271.0, self.navigationController.navigationBar.frame.origin.y, self.navigationController.navigationBar.frame.size.width, self.self.navigationController.navigationBar.frame.size.height);
self.contentView.frame = CGRectMake(271.0, self.contentView.frame.origin.y, self.contentView.frame.size.width, self.contentView.frame.size.height);
This is working, but the first row in the left menu is not "clickable" where the nav bar is supossed to be. Its like the navigation bar is still there capturing the tab events.
Is it correct to do?:
self.navigationController.navigationBar.frame = CGRectMake(271.0, self.navigationController.navigationBar.frame.origin.y, self.navigationController.navigationBar.frame.size.width, self.self.navigationController.navigationBar.frame.size.height);
If not, whats the propper way to achieve what I want?
Heres and image ilustrating what the problem is:
I think it's best to use a custom container controller to do this kind of thing, rather than moving a navigation bar. In IB, this can be set up quite easily. Start with a UIViewController, add a container view to it, and size how you want. Then in the inspector, set its x value to minus its width, which will put it off screen to the left. Then add another container view and size it to be full screen. You can then delete the view controller that you got with that container view, and right drag from the container view to your initial navigation controller (of your already setup UI) to connect it up with an embed segue. The UIViewController that you started with should be made the initial view controller of the storyboard. To move in the side view, I use this code in that custom container controller:
-(void)slideInLeft {
if (isRevealed == NO) {
[UIView animateWithDuration:.6 animations:^{
leftView.center = CGPointMake(leftView.center.x + 100, leftView.center.y);
mainView.center = CGPointMake(mainView.center.x + 100, mainView.center.y);
} completion:^(BOOL finished) {
isRevealed = YES; ;
}];
}else{
[UIView animateWithDuration:.6 animations:^{
leftView.center = CGPointMake(leftView.center.x - 100, leftView.center.y);
mainView.center = CGPointMake(mainView.center.x - 100, mainView.center.y);
} completion:^(BOOL finished) {
isRevealed = NO;
}];
}
}
leftView and mainView are IBOutlets to the 2 container views. I call this method from a button in the main view controller (the root view controller of the navigation controller that's embedded in the large container view):
-(IBAction)callSlideIn:(id)sender {
[(ViewController *)self.navigationController.parentViewController slideInLeft];
}
I found a "fast" way to achieve this (and a bit hacky imo)
I added the leftMenu view to the top view in the views hierachy:
UIWindow* window = [UIApplication sharedApplication].keyWindow;
if (!window)
window = [[UIApplication sharedApplication].windows objectAtIndex:0];
[[[window subviews] objectAtIndex:0] addSubview:self.leftMenu.view];
Now it is les deep than the navigation bar and, of course, its clickable

How to hide custom tab bar button when hidesBottomBarWhenPushed is "TRUE"

I am using the code snippet from Tito to add a custom button to my tab bar:
https://github.com/tciuro/CustomTabBar
(Subclassing UITabbarController and adding a custom button using
// .. created a UIButton *button
[self.view addSubview:button];
)
This works great with my storyboard-based app except for the case of a subview within a navigation controller with the option "Hides bottom bar on push" enabled.
This hides the tab bar as promised, but not the custom button.
Seems like the button should be added as a subview to the tab bar itself?
I tried this ugly code which did not even make the button show up:
for(UIView *view in self.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view addSubview:button];
break;
}
}
Any ideas?
UPDATE:
My solution:
In my ApplicationDelegate i define the following methods, which i call whenever needed in the viewWillAppear or viewWillDisappear methods:
-(void)hideCenterButton:(BOOL)animated
{
if(animated){
[UIView animateWithDuration:0.3
delay:0.0f
options:UIViewAnimationCurveLinear
animations:^{
CGRect frame = self.centerButton.frame;
frame.origin.x = -100;
self.centerButton.frame = frame;
}
completion:^(BOOL finished){
}];
}
}
-(void)showCenterButton:(BOOL)animated
{
if(animated){
[UIView animateWithDuration:0.35
delay:0.0f
options:UIViewAnimationCurveLinear
animations:^{
CGRect frame = self.centerButton.frame;
frame.origin.x = (self.view.superview.frame.size.width / 2) - (self.centerButton.frame.size.width / 2);
self.centerButton.frame = frame;
}
completion:^(BOOL finished){
}];
}
}
I had to set the animation's duration to 0.35s to get a smooth effect in harmony with the tab bar.
Why don't you make button your tabbar's part.
tabBarController.tabBar.addSubView(yourButton)
everything would be solve. cheers!
One easy way to handle this would be to create an instance of the button in .h of your file.
UIButton *customTabButton;
When calling the hides bottom bar on push set the button property to hidden and reset it again in the other views if the bottom bar is visible.
shareFbButton.hidden=YES;
You can check this is the viewDidLoad of all the files and put this line of code if needed to make sure you are displaying the button and hiding the button on all the pages you need.
if(self.tabBarController.tabBar.isHidden){
// set or reset the custom button visibility here
}
This is one way.
I think there are 2 ways you can got with this.
1) try to get the button into a view that is above the old top view controller and the tab bar BUT below the new top view controller that is pushed.
2) animate away the button when the new view controller is pushed.
The first will require mucking with the iOS proprietary view hierarchy which is undocumented, unsupported and could change anytime.
The second will be a matter of making the animation appear smooth enough for your user not to notice. It's not entirely a matter of behaving perfect, just appearing appropriately.
I would personally recommend an animation of the the button disappearing (animate it's alpha to 0) and reappearing based on if your view controller that goes over the tab bar is appearing or disappearing.
The animation for a navigation is (I believe) 0.3 seconds. If the button is in the middle of the tab bar, you'll likely want it invisible as the animating in view controller reaches it (if not sooner) so something between 0.1 and 0.15 seconds could be used to animate it out.
Now this does not make the button behave exactly the same as the tab bar, but with the quickness of the transition being so short, it will be unnoticeable really to the user.
Now just to provide a question for you to ask yourself. Why do you need to push a view controller that overlaps the tab bar? Why is that more desirable/necessary than presenting a modal view controller? If you can strongly argue for it, keep at it and good luck, if it's not necessary however, you may be able to achieve the experience you want with a modal view controller.
Check this one to put a button on the UITabBar. See if it works after with hidesBottoBarWhenPushed.

Animated Subviews

I have a split view controller in my Ipad app, in which the detail view has subviews which are UITableView's.
The functionality I am trying to implement is to get an info view at the same position of a subview when a button(info button) on the subview is pressed. I need to get this info view by animation and that animation is that when the info button is pressed, that subview alone would flip (UIAnimationOptionFlipFromRight) and the info view would show...
This is how try to implement it -
-(void) showInfoView: (id)sender
{
infoView = [[InfoViewController alloc] initWithNibName:#"ViewViewController" bundle:nil];
infoView.view.frame = CGRectMake(250, 300, 200, 200);
[UIView transitionWithView:self.view duration:1
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[self.view addSubview:infoView.view];
}
completion:nil];
}
When I run the simulator and press the info button on any subview, what happens is that the animation happens perfectly, i.e. the subview flips from the right but the infoView is not getting displayed.
It would be great if someone could tell me where I am going wrong here.
The basic steps of performing an animation to onscreen is as follows:
Create the view.
Move it to the initial (offscreen) position
Add to the view hierarchy
Perform the animation.
It seems like you're skipping step 3 and possibly step 2.
Did you try setting the subview frame to the frame of your superview, i.e
info.View.frame = self.view.frame;

Resources